Javascript 如何将deflated/gzip内容与XHR onProgress函数一起使用?
我以前见过很多类似的问题被问到,但我还没有找到一个能准确描述我当前问题的问题,所以下面是: 我有一个页面,它通过AJAX加载一个大的(0.5到10 MB)JSON文档,以便客户端代码可以处理它。一旦文件被加载,我就不会有任何意想不到的问题。但是,下载需要很长时间,因此我尝试利用呈现进度条来向用户指示文档正在加载。这很有效 然后,为了加快速度,我尝试通过gzip和deflate在服务器端压缩输出。这也奏效了,获得了巨大的收益,然而,我的进度条停止了工作 我已经研究了这个问题一段时间,发现如果请求的AJAX资源没有发送适当的Javascript 如何将deflated/gzip内容与XHR onProgress函数一起使用?,javascript,jquery,xmlhttprequest,compression,Javascript,Jquery,Xmlhttprequest,Compression,我以前见过很多类似的问题被问到,但我还没有找到一个能准确描述我当前问题的问题,所以下面是: 我有一个页面,它通过AJAX加载一个大的(0.5到10 MB)JSON文档,以便客户端代码可以处理它。一旦文件被加载,我就不会有任何意想不到的问题。但是,下载需要很长时间,因此我尝试利用呈现进度条来向用户指示文档正在加载。这很有效 然后,为了加快速度,我尝试通过gzip和deflate在服务器端压缩输出。这也奏效了,获得了巨大的收益,然而,我的进度条停止了工作 我已经研究了这个问题一段时间,发现如果请求的
内容长度
头,那么onProgress
事件处理程序就无法按预期运行,因为它不知道下载的时间有多长。发生这种情况时,事件对象上名为lengthComputeable
的属性被设置为false
这是有道理的,所以我尝试使用输出的未压缩和压缩长度显式设置头。我可以验证是否发送了标题,我可以验证我的浏览器是否知道如何解压缩内容。但是onProgress
处理程序仍然报告lengthComputeable=false
所以我的问题是:有没有办法用AJAX Progress API压缩/压缩内容?如果有,我现在做错了什么
这是资源在Chrome网络面板中的显示方式,显示压缩正在工作: 这些是相关的请求头,表明请求是AJAX,并且
接受编码
设置正确:
GET/dashboard/reports/ajax/load HTTP/1.1
连接:保持活力
缓存控制:没有缓存
Pragma:没有缓存
接受:application/json,text/javascript,*/*;q=0.01
X-request-With:XMLHttpRequest
用户代理:Mozilla/5.0(Macintosh;英特尔Mac OS X 10_7_5)AppleWebKit/537.22(KHTML,如Gecko)Chrome/25.0.1364.99 Safari/537.22
接受编码:gzip、deflate、sdch
接受语言:en-US,en;q=0.8
接受字符集:ISO-8859-1,utf-8;q=0.7,*;q=0.3
这些是相关的响应标题,表明内容长度
和内容类型
设置正确:
HTTP/1.1200正常
缓存控制:无存储,无缓存,必须重新验证,后检查=0,预检查=0
内容编码:deflate
内容类型:application/json
日期:2013年2月26日星期二18:59:07 GMT
到期时间:1981年11月19日星期四格林威治标准时间08:52:00
P3P:CP=“我们的”
Pragma:没有缓存
服务器:Apache/2.2.8(Unix)mod_ssl/2.2.8 OpenSSL/0.9.8g PHP/5.4.7
X-Powered-By:PHP/5.4.7
内容长度:223879
连接:保持活力
值得一提的是,我已经在标准(http)和安全(https)连接上尝试了这一点,没有任何区别:内容在浏览器中加载良好,但没有被Progress API处理
根据,我尝试将服务器端切换到gzip编码,但没有成功或更改。以下是相关的响应标题:
HTTP/1.1200正常
缓存控制:无存储,无缓存,必须重新验证,后检查=0,预检查=0
内容编码:gzip
内容类型:application/json
日期:2013年3月4日星期一格林尼治标准时间22:33:19
到期时间:1981年11月19日星期四格林威治标准时间08:52:00
P3P:CP=“我们的”
Pragma:没有缓存
服务器:Apache/2.2.8(Unix)mod_ssl/2.2.8 OpenSSL/0.9.8g PHP/5.4.7
X-Powered-By:PHP/5.4.7
内容长度:28250
连接:保持活力
重复一次:内容正在被正确下载和解码,这只是我遇到麻烦的ProgressAPI
佩尔,以下是请求:
$.ajax({
url: '<url snipped>',
data: {},
success: onDone,
dataType: 'json',
cache: true,
progress: onProgress || function(){}
});
尝试将服务器编码更改为gzip。 您的请求头显示了三种可能的编码(gzip、deflate、sdch),因此服务器可以选择这三种编码中的任何一种。通过响应头,我们可以看到您的服务器选择使用deflate进行响应 Gzip是一种编码格式,除了额外的页眉和页脚(包括原始未压缩长度)和不同的校验和算法外,还包括一个deflate有效负载: Deflate有一些问题。由于处理不正确解码算法的遗留问题,deflate的客户端实现必须进行愚蠢的检查,以确定它们处理的是哪一个实现,不幸的是,它们仍然经常出错: 在你的问题中,浏览器可能会看到一个泄气文件从管道中流下来,然后举起手臂说,“当我甚至不知道如何解码这个东西时,你怎么能指望我担心进度是否正确,人类?”
如果您切换服务器配置,使响应是gzip(即gzip显示为内容编码),我希望您的脚本能够像您希望/预期的那样工作。不要因为没有本机解决方案而陷入困境;一行黑客可以在不影响Apache配置的情况下解决您的问题(在某些主机中是禁止的或非常受限的): PHP拯救:
var size = <?php echo filesize('file.json') ?>;
var size=;
就这样,您可能已经知道了其余内容,但作为参考:
<script>
var progressBar = document.getElementById("p"),
client = new XMLHttpRequest(),
size = <?php echo filesize('file.json') ?>;
progressBar.max = size;
client.open("GET", "file.json")
function loadHandler () {
var loaded = client.responseText.length;
progressBar.value = loaded;
}
client.onprogress = loadHandler;
client.onloadend = function(pe) {
loadHandler();
console.log("Success, loaded: " + client.responseText.length + " of " + size)
}
client.send()
</script>
var progressBar=document.getElementById(“p”),
client=new XMLHttpRequest(),
大小=;
progressBar.max=大小;
client.open(“GET”、“file.json”)
函数loadHandler(){
加载的变量=client.responseText.length;
progressBar.value=已加载;
}
client.onprogress=loadHandler;
client.onloadend=函数(pe){
loadHandler();
log(“成功,加载:“+client.responseText.length+”,大小为“+size”)
}
client.send()
现场示例:<
<script>
var progressBar = document.getElementById("p"),
client = new XMLHttpRequest(),
size = <?php echo filesize('file.json') ?>;
progressBar.max = size;
client.open("GET", "file.json")
function loadHandler () {
var loaded = client.responseText.length;
progressBar.value = loaded;
}
client.onprogress = loadHandler;
client.onloadend = function(pe) {
loadHandler();
console.log("Success, loaded: " + client.responseText.length + " of " + size)
}
client.send()
</script>
function loader(onDone, onProgress, url, data)
{
// onDone = event handler to run on successful download
// onProgress = event handler to run during a download
// url = url to load
// data = extra parameters to be sent with the AJAX request
var content_length = null;
self.meta_xhr = $.ajax({
url: url,
data: data,
dataType: 'json',
type: 'HEAD',
success: function(data, status, jqXHR)
{
content_length = jqXHR.getResponseHeader("X-Content-Length");
}
});
self.xhr = $.ajax({
url: url,
data: data,
success: onDone,
dataType: 'json',
progress: function(jqXHR, evt)
{
var pct = 0;
if (evt.lengthComputable)
{
pct = 100 * evt.position / evt.total;
}
else if (self.content_length != null)
{
pct = 100 * evt.position / self.content_length;
}
onProgress(pct);
}
});
}
loader(function(response)
{
console.log("Content loaded! do stuff now.");
},
function(pct)
{
console.log("The content is " + pct + "% loaded.");
},
'<url here>', {});
header("X-Content-Length: ".strlen($payload));
if ($_SERVER['REQUEST_METHOD'] == "HEAD")
{
exit;
}
request.onProgress = function (e) {
var contentLength;
if (e.lengthComputable) {
contentLength = e.total;
} else {
contentLength = parseInt(e.target.getResponseHeader('x-decompressed-content-length'), 10);
}
progressIndicator.update(e.loaded / contentLength);
};
<IfModule mod_deflate.c>
DeflateBufferSize 10000000
</IfModule>
<IfModule mod_headers.c>
Header set Access-Control-Expose-Headers "Content-Length"
</IfModule>
var total = e.total;
if(!e.lengthComputable){
total = e.target.getResponseHeader('content-length') * 2.2;
}
// Some times 100 reached in the progress event more than once.
if(preloadedResources < resourcesLength && progressPercentage < 100) {
canIncreaseCounter = true;
}
if(progressPercentage >= 100 && canIncreaseCounter && preloadedResources < resourcesLength) {
preloadedResources++;
canIncreaseCounter = false;
}