XMLHttpRequest进度事件与gzip压缩内容的问题(除了FireFox)

4

在我的应用程序中,我使用XMLHttpRequest API请求大型JSON文件。这按预期工作。

我想在用户等待时显示进度条。一些JSON文件大小在6到10MB以上,因此进度条可以帮助提高整体体验。

这是我正在做的示例:

var progress = document.getElementById('progress');

function getData(url) {
    var req = new XMLHttpRequest();

  req.onprogress = function(event) {
    if (event.lengthComputable) {
      progress.value = event.loaded / event.total * 100;
    } else {
      console.log('lengthComputable failed');
    }
  }

  req.onload = function() {
    console.log('Finished loading');
    // ... handle data
  }

  req.open('GET', url, true);
  req.overrideMimeType('application/json');
  req.send(null);
}

getData('https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson');

此外,在 jsfiddle 上也有:https://jsfiddle.net/ctL5f73s/1/ 如果内容没有经过 gzip 压缩,进度条在我测试过的所有浏览器上都可以正常工作。但是如果服务器将其发送为 gzip,则仅 Firefox 可以使用。
为了背景,我正在从 GitHub 请求数据。我理解的是,他们将所有资产作为 gzip 提供,并且我无法控制它。
我还知道 XHR 的进度事件应处理压缩内容。其中大部分内容都超出了我的理解范围,但我了解到的是,当内容被压缩时,lengthComputable 的处理方式不会改变。
响应标头 中,我看到 Content-EncodingContent-Length 是正确的: enter image description here 问题是:是否有办法使进度事件在 FireFox 之外的浏览器中与 gzip 内容一起工作?
如果不可能,是否有人可以指导我使用替代方案?最好是本机 JS 而不是库。
我不介意兼容性太远,但如果最新版本的 Chrome 无法使用,则会出现问题。

我很好奇 - 你有没有得到这个问题的答案? - Ryan Alberts
很不幸,目前还没有。 - 1cgonza
1
我们采用的一种替代方案是在服务器端添加一个附加头:X-Uncompressed-Content-Length: ${file.length},并在 JavaScript 端解析它,这样可以确保 100% 的正确性。 - oligofren
2个回答

6

我做了类似的事情。虽然不是完全一样,但已经足够好了。

req.onprogress = function(event) {
  if (event.lengthComputable) {
    progress.value = event.loaded / event.total * 100
  } else {
    var total = req.getResponseHeader('content-length')
    var encoding = req.getResponseHeader('content-encoding')
    if (total && encoding && (encoding.indexOf('gzip') > -1)) {
      // assuming average gzip compression ratio to be 25%
      total *= 4 // original size / compressed size
      progress.value = Math.min(100, event.loaded / total * 100)
    } else {
      console.log('lengthComputable failed')
    }
  }
}

显然,有时进度会跳到100%,有时会停在100%,但只是短暂的时间,几乎不会被注意到。


1
问题可能出在你的Content-Type上:text/plain。尝试在shell命令行中使用curl的GET方法(不带--compressed参数,以立即查看二进制输出)——是否可以立即看到响应?例如,Chrome对于"text/plain"不会立即触发onprogress回调,但如果你使用"application/json",它会触发。尝试在响应头中使用"Content-Type: application/json",看看是否有所不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接