jQuery ajax在HTTP 206(部分内容)时导致Chrome崩溃

3
这件事情困扰我已经有一段时间了,但到目前为止我在网络上找不到原因/解决方案。以下是设置说明:
我有一个JS客户端在浏览器上运行,向内部系统发出搜索请求。这些请求只是GET请求,没有什么特别的。它们返回一个URL,当搜索结果可用时,将把结果放入其中。
然后,我会定期(比如每5分钟)轮询给定的URL以获取结果,并处理数据以呈现给用户。该URL指向一个gzip压缩的结果文件,它只是一个普通的文本文件(ASCII格式)。
现在...搜索结果通常包含几百行文本,但有时会有数十万行文本,有时会有7-10MB大小的文本(解压后)。这就是浏览器显示悲伤标签页的地方。
(无需指出这种方法存在的安全问题,它们很多且高度有效)。
没有什么特别的 - 只是调用一个
$.ajax({
    url: '/cgi-bin/ajax_gz.cgi',
    type: 'POST',
    data: 'curl -k "' + self.url_res + '"',
    dataType: 'html',
    success: function (_data, _status, _xhr) {
        self.update_result(_data, _status, _xhr);
    },
    error: function (_xhr, _status, _error) {
        self.set_status(Status.ACK);
    },
    timeout: 5 * ONE_MINUTE
});

这里的 ajax_gz.cgi 只是一个简单的代理,允许我的 JS 通过中继 curl 请求来从不同的域名获取数据:

#!/bin/bash
echo "Content-type: text/html"
echo "Content-encoding: gzip"
echo ""
/bin/bash

返回的确实是一个经过gzip压缩的HTML,所以我设置了相应的头信息。我想我可以在ajax()的配置中更新头信息,但这似乎是一个更简单的方法。

successerror函数从未被调用,超时(5分钟)也不是问题——所有操作都在局域网内完成,整个传输时间不到半分钟。

我可以在选项卡中毫无问题地打开该URL,并显示未经压缩的ASCII文本。但是当使用jQuery的ajax()检索数据时,我面临着一个令人沮丧的页面(几乎每次都是如此,但仅针对“部分内容”HTTP 206响应)。

我错过了什么?尝试在JS调试器中“逐步执行”并在readyState===4的函数处停止,我能够捕获响应。它是一个HTTP 200响应,包含完整的文本(从开头的<html>标记一直到带有108K行的单个<pre>标记的结尾)。 一旦我得到了响应并尝试“展开”this值,我就会得到一个令人沮丧的页面。

更新:通过逐步执行jQuery的代码并停在readyState===4的函数处,我能够捕获响应。它是一个HTTP 200响应,包含完整的文本(从开头的<html>标记一直到带有108K行的单个<pre>标记的结尾)。 一旦我得到了响应并尝试“展开”this值,我就会得到一个令人沮丧的页面。


除了Chrome浏览器之外,其他浏览器表现如何? - apsillers
你有没有尝试使用最新版本的jQuery?可以使用.done()、.fail()和.complete()代替.success()和.error()。另外,在尝试跨域之前,你能否在开发环境中模拟一下呢? - Sam Deering
一旦您停在readyState == 4语句处,您能否一直步进直到崩溃?您能执行的最后一行是什么? - jsha
@jsha - 在Chrome标签页中仅下载目标.gz文件就会导致浏览器崩溃。 - YePhIcK
@apsillers - 我没有在IE或FF中尝试,但Safari会崩溃。 - YePhIcK
2个回答

0

由于您的bash代理(天哪!)不执行任何gzip压缩,而curl通常会解压带有Content-Encoding:gzip的任何接收到的内容,我假设来自您内部服务器的响应已经被压缩,但没有Content-Encoding头。

听起来您的curl脚本正在从内部服务器获取206,对吧?这有点奇怪,因为服务器只应在响应Range标头时返回206。然而,既然已经确定了这一点,您将获得部分响应的gzip内容,并将其作为200传递给Chrome。当然,这不应该导致Chrome崩溃,但可能存在错误。

也许尝试解压:

#!/bin/bash
echo "Content-type: text/html"
echo ""
curl -k "`cat`" | gunzip

您还需要更改您的Ajax数据源:

data: self.url_res,

如果失败了,尝试使用 -i 参数从 curl 中捕获完整的头部信息以进行进一步调试。

猜得不错,但并不完全正确。我正在使用一个特殊的gzip友好版本的脚本,它会放置一个正确的Content-type头。但是curl不会自动解压返回的数据。 - YePhIcK

0

我认为你遇到了Chrome的内存限制。根据this,Chrome对AJAX调用可能有3000个字符的限制。

正如你所注意到的,开发者工具显示了所有内容,但当将其读取以返回给jQuery时,它会达到某种形式的上限。你可以尝试将响应限制在该限制以下,看看是否有效?或者尝试使用另一个浏览器?

如果这是问题所在,你可以尝试分部分返回结果。返回几个部分可能可以绕过限制。


那段代码肯定已经成功地解析了超过3K个字符。我曾经看到它能够处理多达3M的字符。服务器端不受我的控制,所以无法更改其返回结果。 - YePhIcK

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