【发布时间】:2014-07-14 20:12:07
【问题描述】:
我正在使用 XMLHttpRequest 和 Range 标头以 5 MB 的块下载约 50 MB 的文件。一切都很好,除了检测我何时下载了最后一个块。
这是 first 块的请求和响应的屏幕截图。注意 Content-Length 是 1024 * 1024 * 5 (5 MB)。另请注意,服务器正确响应前 5 MB,并在 Content-Range 标头中正确指定了整个文件的大小(在/ 之后):
当我将响应正文复制到文本编辑器 (Sublime) 中时,我只得到 5,242,736 个字符,而不是 Content-Length 所示的预期 5,242,880 个字符:
为什么缺少 144 个字符?对于下载的每个块都是如此,尽管确切的差异会有所不同。
然而,特别奇怪的是 last 块。服务器以文件的最后约 2.9 MB(而不是整个 5 MB)进行响应,并且显然在响应中正确地指出了这一点:
请注意,我正在请求下一个 5 MB(即使它超出了总文件大小)。没什么大不了的,服务器以文件的最后一部分进行响应,并且标头指示返回的实际字节范围。
但真的吗?
当我使用 Javascript 调用 xhr.getResponseHeader("Content-Length") 时,我在 Chrome 中看到了不同的故事:
XMLHttpRequest 对象告诉我在文件末尾之外又下载了 5 MB。 xhr 对象有什么我不明白的地方吗?
更更奇怪的是它可以在 Firefox 30 中按预期工作:
所以在xhr.responseText.length 与Content-Length 不匹配以及这些标头在xhr 对象和网络工具之间不一致,我不知道如何解决这个问题。
造成这些差异的原因是什么?
更新:我已经确认服务器本身正在正确发送请求,尽管最后一个块的请求中的 Range 标头超出了范围。这是原始 HTTP 请求的输出,感谢好的 'ol telnet:
HTTP/1.1 206 Partial Content
Server: nginx/1.4.5
Date: Mon, 14 Jul 2014 21:50:06 GMT
Content-Type: application/octet-stream
Content-Length: 2987360
Last-Modified: Sun, 13 Jul 2014 22:05:10 GMT
Connection: keep-alive
ETag: "53c30296-2fd9560"
Content-Range: bytes 47185920-50173279/50173280
所以看起来 Chrome 出现了故障。这应该作为错误提交吗?在哪里?
【问题讨论】:
-
xhr.responseText.length 是响应中的字符数,而不是 Content-Length 标头中指示的字节数。某些 unicode 字符(或强制转换为 unicode 的二进制位)每个字符使用多个字节。 chrome 可能会第二次猜测无效的范围标头(例如与文件结尾重叠的标头),firefox 也可能如此,但似乎只有一种方法(ff)适用于您的情况。修复 REQUEST 标头,然后重试。
-
谢谢@dandavis。看我的更新。我直接在 telnet 中运行了请求,服务器的原始输出符合预期,这意味着(我认为?)Chrome 在发出 XMLHttpRequest 或其他东西时一定会出现故障......
-
我建议 chrome 可能正在做一些特别的事情,这里没有显示,通过内部将请求与响应联系起来。看起来服务器的输出很好,但 chrome 也可能会考虑来自请求的输入(特别是范围 0-52/50),这告诉它期待更多。当您是浏览器时,有时聪明是愚蠢的。
-
@dandavis 我想我明白你在说什么,Chrome 可能会假设它不应该做的事情。但是......输入/请求不包括总文件大小:只有响应的 Content-Range 有。
-
我要说的是,您在第一个屏幕截图中显示的 Range 请求标头(0-5242879 标头)可能会欺骗 chrome。为什么你每次都回复我不知道的回复,但如果我是你,我会尝试更改请求......
标签: javascript ajax google-chrome firefox xmlhttprequest