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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 12:09:02  来源:igfitidea点击:

Why is ProgressEvent.lengthComputable false?

javascriptxmlhttprequest

提问by Simon Cave

I am loading a JSON file using XMLHttpRequest in Google Chrome, Safari and Firefox. In all three browsers I am receiving ProgressEvents which correctly show the .loadedproperty. However the .lengthComputableproperty is false and the .totalproperty is zero. I have checked that the Content-LengthHTTP header is being sent and is correct - it is. The response is being gzip-encoded, but the Content-lengthcorrectly shows the encoded length (before decompression).

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

Why would the total length not be available in my ProgressEvents?

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

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.login that code is showing hundreds of events with up to date .loadeds but .lengthComputableis always false and .totalis always zero. selfrefers to the object responsible for this XMLHttpRequest.

注意:该console.log代码中的 显示了数百个具有最新.loadeds的事件,但.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 loadedand totalrefer to the compressed or uncompressed content. SinceJun 26, 2014 the XMLHttpRequest specificationsmake clear they should refer to the transmitted (compressed) content:

这似乎是由规格一次是不明的,如果引起loadedtotal指压缩或解压缩的内容。20146 月 26 日起,XMLHttpRequest 规范明确指出它们应该引用传输(压缩)的内容:

6.1. Firing events using the ProgressEventinterface

[...] given transmittedand length[...] fire an event [...] ProgressEvent, with the loadedattribute initialized to transmitted, and if lengthis not 0, with the lengthComputableattribute initialized to true and the totalattribute initialized to length.

6.1. 使用ProgressEvent接口触发事件

[...] 给定的传输长度[...] 触发事件 [...] ProgressEventloaded属性初始化为传输,如果长度不为 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, totalstays to be 0 and lengthComputableis not set

编码时,total保持为 0lengthComputable且未设置

The event itself is still fired, and event.loadedis still populated. But Chrome is decompressing gzip'd content on the fly and (today) sets loadedto the resulting decompressed length, not to the transmittedlength. This cannot be compared to the value of the Content-Lengthheader, as that's the length of the compressedcontent, so loadedwill become larger than the content length.

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

At best one could assume some compression factor to compare loadedagainst 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.

##代码##