为什么ProgressEvent.lengthComputable为false?

Sim*_*ave 16 javascript xmlhttprequest

我正在使用Google Chrome,Safari和Firefox中的XMLHttpRequest加载JSON文件.我收到ProgressEvent的所有三个浏览器都正确显示了该.loaded属性.但是该.lengthComputable属性为false且.total属性为零.我已经检查过Content-LengthHTTP标头是否正在发送并且是正确的 - 它是.响应是gzip编码的,但Content-length正确显示编码长度(在解压缩之前).

为什么我的ProgressEvents中总长度不可用?

以下是标题:

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
Run Code Online (Sandbox Code Playgroud)

注意:该文件通过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);
Run Code Online (Sandbox Code Playgroud)

注意:该console.log代码中显示了数百个具有最新值.loaded的事件,但.lengthComputable始终为false且.total始终为零.self是指对此负责的对象XMLHttpRequest.

Wil*_*elm 17

如果XMLHttpRequestProgressEvent中的lengthComputable为false,则表示服务器从未在响应中发送Content-Length标头.

如果你使用nginx作为代理服务器,这可能是罪魁祸首,特别是如果它没有将Content-Length头从上游服务器通过代理服务器传递到浏览器.

  • 或者,很多年后,即使在Chrome浏览器中使用了gzip格式的内容,即使设置了正确的标题也是如此。:-( (2认同)

Arj*_*jan 8

Meanwhile 2017, things are fine in Firefox, but Chrome does not show the progress for gzip'd content.

This seems to be caused by the specifications once being unclear if loaded and total refer to the compressed or uncompressed content. Since Jun 26, 2014 the XMLHttpRequest specifications make clear they should refer to the transmitted (compressed) content:

6.1. Firing events using the ProgressEvent interface

[...] given transmitted and length [...] fire an event [...] ProgressEvent, with the loaded attribute initialized to transmitted, and if length is not 0, with the lengthComputable attribute initialized to true and the total attribute initialized to length.

However, the 2015 Chromium bug report "XHR's progress events should handle gzipped content" explains that things were different, and states:

when encoded, total stays to be 0 and lengthComputable is not set

该事件本身仍被触发,并且event.loaded仍在填充。但是Chrome正在即时解压缩gzip的内容,并且(今天)设置loaded为最终的解压缩长度,而不是传输长度。不能将其与Content-Length标头的值进行比较,因为这是压缩内容的长度,因此loaded它将大于内容长度。

在最好的情况可以假设一些比较压缩因子loaded反对Content-Length,或使服务器添加一些自定义头,可以提供原始长度或真压缩因子,假设Chrome的上即时解压缩不会改变。

我不知道Chrome对于的其他值会做什么Content-Encoding


小智 5

使用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);
Run Code Online (Sandbox Code Playgroud)