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
Set the Content-Length in the controller code. This will set the 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 + '%';
}
};
Just set in PHP or apache/nginx
header("Content-Encoding: none");
problem solved.
use req.upload.addEventListener for upload
req.addEventListener event.lengthComputable will always be 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);
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 theloaded
attribute initialized to transmitted, and if length is not 0, with thelengthComputable
attribute initialized to true and thetotal
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 andlengthComputable
is not set
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 transmitted length. This cannot be compared to the value of the Content-Length
header, as that's the length of the compressed content, so loaded
will become larger than the content length.
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.
I've no idea what Chrome does for other values for Content-Encoding
.
If lengthComputable is false within the XMLHttpRequestProgressEvent, that means the server never sent a Content-Length header in the response.
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.