javascript 为什么 ProgressEvent.lengthComputable 是假的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11127654/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is ProgressEvent.lengthComputable false?
提问by Simon Cave
I am loading a JSON file using XMLHttpRequest in Google Chrome, Safari and Firefox. In all three browsers I am receiving ProgressEvent
s which correctly show the .loaded
property. However the .lengthComputable
property is false and the .total
property is zero. I have checked that the Content-Length
HTTP header is being sent and is correct - it is. The response is being gzip-encoded, but the Content-length
correctly shows the encoded length (before decompression).
我在 Google Chrome、Safari 和 Firefox 中使用 XMLHttpRequest 加载 JSON 文件。在所有三个浏览器中,我都收到了ProgressEvent
正确显示.loaded
属性的s 。但是,该.lengthComputable
属性为 false,并且该.total
属性为零。我已经检查过Content-Length
HTTP 标头是否正在发送并且是正确的 - 是的。响应是 gzip 编码的,但Content-length
正确显示了编码长度(解压缩前)。
Why would the total length not be available in my ProgressEvent
s?
为什么总长度在我的ProgressEvent
s 中不可用?
Here are the headers:
以下是标题:
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: 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);
.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
Note: the file is being served via Google App Engine.
注意:该文件是通过 Google App Engine 提供的。
Here is the JavaScript:
这是 JavaScript:
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);
Note: The console.log
in that code is showing hundreds of events with up to date .loaded
s but .lengthComputable
is always false and .total
is always zero. self
refers to the object responsible for this XMLHttpRequest
.
注意:该console.log
代码中的 显示了数百个具有最新.loaded
s的事件,但.lengthComputable
始终为假且.total
始终为零。self
指负责 this 的对象XMLHttpRequest
。
回答by Wilhelm
If lengthComputable is false within the XMLHttpRequestProgressEvent, that means the server never sent a Content-Length header in the response.
如果 XMLHttpRequestProgressEvent 中的 lengthComputable 为 false,则意味着服务器从未在响应中发送 Content-Length 标头。
If you're using nginx as a proxy server, this might be the culprit, especially if it's not passing the Content-Length header from the upstream server through the proxy server to the browser.
如果您使用 nginx 作为代理服务器,这可能是罪魁祸首,特别是如果它没有将 Content-Length 标头从上游服务器通过代理服务器传递到浏览器。
回答by Arjan
Meanwhile 2017, things are fine in Firefox, but Chrome does not show the progress for gzip'd content.
与此同时,2017 年,Firefox 一切正常,但 Chrome 没有显示 gzip 内容的进度。
This seems to be caused by the specifications once being unclear if loaded
and total
refer to the compressed or uncompressed content. SinceJun 26, 2014 the XMLHttpRequest specificationsmake clear they should refer to the transmitted (compressed) content:
这似乎是由规格一次是不明的,如果引起loaded
并total
指压缩或解压缩的内容。自2014年6 月 26 日起,XMLHttpRequest 规范明确指出它们应该引用传输(压缩)的内容:
6.1. Firing events using the
ProgressEvent
interface[...] given transmittedand length[...] fire an event [...]
ProgressEvent
, with theloaded
attribute initialized to transmitted, and if lengthis not 0, with thelengthComputable
attribute initialized to true and thetotal
attribute initialized to length.
6.1. 使用
ProgressEvent
接口触发事件[...] 给定的传输和长度[...] 触发事件 [...]
ProgressEvent
,loaded
属性初始化为传输,如果长度不为 0,则lengthComputable
属性初始化为 true,total
属性初始化为长度。
However, the 2015 Chromium bug report "XHR's progress events should handle gzipped content"explains that things were different, and states:
但是,2015 年 Chromium 错误报告“XHR 的进度事件应该处理 gzipped 内容”解释说情况有所不同,并指出:
when encoded,
total
stays to be 0 andlengthComputable
is not set
编码时,
total
保持为 0lengthComputable
且未设置
The event itself is still fired, and event.loaded
is still populated. But Chrome is decompressing gzip'd content on the fly and (today) sets loaded
to the resulting decompressed length, not to the transmittedlength. This cannot be compared to the value of the Content-Length
header, as that's the length of the compressedcontent, so loaded
will become larger than the content length.
事件本身仍然被触发,并且event.loaded
仍然被填充。但是 Chrome 正在即时解压缩 gzip 的内容,并且(今天)设置loaded
为结果解压缩长度,而不是传输长度。这无法与Content-Length
标头的值进行比较,因为这是压缩内容的长度,因此loaded
会大于内容长度。
At best one could assume some compression factor to compare loaded
against Content-Length
, or make the server add some custom header to provide the original length or the true compression factor, assuming Chrome's on-the-fly decompression will not change.
在最好的情况可以假设一些比较压缩因子loaded
反对Content-Length
,或使服务器添加一些自定义头,可以提供原始长度或真压缩因子,假设Chrome的上即时解压缩不会改变。
I've no idea what Chrome does for other values for Content-Encoding
.
我不知道 Chrome 对Content-Encoding
.
回答by user7694431
use req.upload.addEventListenerfor upload
使用req.upload.addEventListener上传
req.addEventListenerevent.lengthComputable will always be false
req.addEventListenerevent.lengthComputable 将始终为 false
header("Content-Encoding: none");
回答by waza123
Just set in PHP or apache/nginx
只需在 PHP 或 apache/nginx 中设置
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/[email protected]');
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 + '%';
}
};
problem solved.
问题解决了。
回答by Andre Rubnikowich
Set the Content-Length in the controller code. This will set the event.lengthComputable
.
在控制器代码中设置 Content-Length。这将设置event.lengthComputable
.