我在Google Chrome,Safari和Firefox中使用XMLHttpRequest加载JSON文件。在所有三个浏览器中,我都会收到ProgressEvent
个正确显示.loaded
属性的内容。但是.lengthComputable
属性为false,.total
属性为零。我已经检查过Content-Length
HTTP标头正在发送并且是正确的 - 它是。响应是gzip编码的,但Content-length
正确显示编码长度(在解压缩之前)。
为什么我的ProgressEvent
s中的总长度不可用?
以下是标题:
HTTP/1.1 200 OK
ETag: "hKXdZA"
Date: Wed, 20 Jun 2012 20:17:17 GMT
Expires: Wed, 20 Jun 2012 20:17:17 GMT
Cache-Control: private, max-age=3600
X-AppEngine-Estimated-CPM-US-Dollars: $0.000108
X-AppEngine-Resource-Usage: ms=2 cpu_ms=0 api_cpu_ms=0
Content-Type: application/json
Content-Encoding: gzip
Server: Google Frontend
Content-Length: 621606
注意:该文件是通过Google App Engine提供的。
这是JavaScript:
var req;
if (window.XMLHttpRequest){
req = new XMLHttpRequest();
if(req.overrideMimeType){
req.overrideMimeType( "text/json" );
}
}else{
req = new ActiveXObject('Microsoft.XMLHTTP');
}
// Listen for progress events
req.addEventListener("progress", function (event) {
console.log(event, event.lengthComputable, event.total);
if (event.lengthComputable) {
self.progress = event.loaded / event.total;
} else if (this.explicitTotal) {
self.progress = Math.min(1, event.loaded / self.explicitTotal);
} else {
self.progress = 0;
}
self.dispatchEvent(Breel.Asset.ON_PROGRESS);
}, false);
req.open('GET', this.url);
注意:该代码中的console.log
显示了数百个最新.loaded
s的事件,但.lengthComputable
始终为false,.total
始终为零。 self
指的是负责此XMLHttpRequest
的对象。
答案 0 :(得分:17)
如果XMLHttpRequestProgressEvent中的lengthComputable为false,则表示服务器从未在响应中发送Content-Length标头。
如果你使用nginx作为代理服务器,这可能是罪魁祸首,特别是如果它没有将Content-Length头从上游服务器通过代理服务器传递到浏览器。
答案 1 :(得分:5)
与2017年同期,Firefox的情况很好,但Chrome没有显示gzip内容的进展。
这似乎是由于loaded
和total
引用压缩或未压缩内容后一直不清楚的规范引起的。 Since 2014年6月26日the XMLHttpRequest specifications明确指出他们应该参考传输(压缩)的内容:
6.1。使用
发射事件ProgressEvent
界面[...] 传输和长度 [...]用[{1]
ProgressEvent
激活事件[...]loaded
初始化为传输的属性,如果 length 不为0,则lengthComputable
属性初始化为true且total
属性初始化为< EM>长度
然而,2015年Chromium错误报告"XHR's progress events should handle gzipped content"解释说情况有所不同,并指出:
编码时,
total
保持为0且未设置lengthComputable
事件本身仍然被触发,event.loaded
仍然填充。但Chrome正在动态解压缩gzip内容,并且(今天)将loaded
设置为生成的解压缩长度,而不是传输的长度。这不能与Content-Length
标头的值进行比较,因为这是压缩内容的长度,因此loaded
将变得大于内容长度。
充其量可以假设一些压缩因子将loaded
与Content-Length
进行比较,或者让服务器添加一些自定义标头以提供原始长度或真正的压缩因子,假设Chrome是on-the-飞行减压不会改变。
我不知道Chrome为Content-Encoding
的其他值做了什么。
答案 2 :(得分:4)
使用 req.upload.addEventListener 进行上传
req.addEventListener event.lengthComputable将始终为false
req.upload.addEventListener("progress", function (event) {
console.log(event, event.lengthComputable, event.total);
if (event.lengthComputable) {
self.progress = event.loaded / event.total;
} else if (this.explicitTotal) {
self.progress = Math.min(1, event.loaded / self.explicitTotal);
} else {
self.progress = 0;
}
self.dispatchEvent(Breel.Asset.ON_PROGRESS);
}, false);
答案 3 :(得分:0)
只需在PHP或apache / nginx中设置
即可header("Content-Encoding: none");
问题解决了。
答案 4 :(得分:0)
在控制器代码中设置Content-Length。这将设置event.lengthComputable
。
var fileSize = new FileInfo(filePathAbs).Length;
context.Response.AddHeader("Content-Length", fileSize.ToString());
context.Response.AddHeader("content-disposition", "inline;filename=" + fileName);
var req = new XMLHttpRequest();
req.open('GET', '/EReader/GetDocument?p=@Model.EncodedTempFilePath');
req.responseType = "arraybuffer";
req.onprogress = function (event) {
if (event.lengthComputable) {
percentage = Math.floor(event.loaded * 100 / event.total); // give the percentage
var elem = document.getElementById("bar");
elem.style.width = percentage + '%';
}
};