【问题标题】:Firefox randomly close XMLHttpRequest connection if inactive. Why?如果不活动,Firefox 会随机关闭 XMLHttpRequest 连接。为什么?
【发布时间】:2016-04-21 16:41:23
【问题描述】:

在 JavaScript 类中,一个 XMLHttpRequest 连接到服务器。 服务器正在缓慢地发送数据。这在 Chromium 中运行良好,但 Firefox 在随机时间(约 4 秒到约 70 秒之间)后关闭连接。

为什么 Firefox 会关闭连接?以及如何避免这种情况?

简化的JS代码:

    var options = {};
    options['header']=
        { 'Cache-Control':'no-cache, max-age=0', 
            'Content-type': 'application/octet-stream',
            'Content-Disposition': 'inline'
        };

    // Get request information
    this.http = new XMLHttpRequest();
    this.http.onreadystatechange = _streamingResponse.bind(this);
    this.http.open('post', url, true);
    for (var i in options['header'])
    {
        this.http.setRequestHeader(i, options['header'][i]);
    }
    this.http.send('');

对于 PHP 部分,类似于:

sleep(200); //wait long time, so firefox close the socket.

如果服务器每隔几秒 (

连接关闭: - 就绪状态 = 4 - 状态 = 0

服务器似乎是正确的,因为在 Chromium 中它可以正常工作。

完整的测试代码:

test.html

<html>
<header>
</header>
<body>
</body>

<script type="application/javascript">

    function log( msg )
    {
        document.body.appendChild(document.createElement('div').appendChild(document.createTextNode(msg)));
        document.body.appendChild(document.createElement('br'));
    }

    function request(url)
    {
        function _streamingResponse()
        {
            if (4==this.http.readyState)
            {
                log('Done: ' + this.http.status);
            }
            else if (3==this.http.readyState)
            {
                var text = this.http.response.substr(this.lastRequestPos);
                this.lastRequestPos = this.http.response.length;
                log('Update: ' + text);
            }
        }

        var options = {};
        options['header']=
            { 'Cache-Control':'no-cache, max-age=0', 
                'Content-type': 'application/octet-stream',
                'Content-Disposition': 'inline'
            };

        this.lastRequestPos=0;

        // Get request information
        this.http = new XMLHttpRequest();
        this.http.onreadystatechange = _streamingResponse.bind(this);
        this.http.open('post', url, true);
        for (var i in options['header'])
        {
            this.http.setRequestHeader(i, options['header'][i]);
        }
        this.http.send('');
        log('Request sent!');
    }

    req = new request('./test.php');
</script>
</html>

test.php

<?php

$timer = 60;

ignore_user_abort(true);
set_time_limit(0);

// Turn off output buffering and compression
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
while (ob_get_level() > 0) {
    $level = ob_get_level();
    ob_end_clean();
    if (ob_get_level() == $level) break;
}
if (function_exists('apache_setenv')) {
    apache_setenv('no-gzip', '1');
    apache_setenv('dont-vary', '1');
}

// Set header for streaming
header('Content-type: application/octet-stream');
flush();

// Send information
sleep($timer);
echo '<yes></yes>';
flush();

?>

附加说明:Firefox 43.0.03、Chromium 47.0.2526

已编辑:

为超时设置回调它不会触发。我断定这不是超时。

this.http.timeout = 2000;
this.http.ontimeout = _streamingTimeout.bind(this);

【问题讨论】:

标签: javascript http firefox xmlhttprequest


【解决方案1】:

进一步搜索后,我在 Mozilla 中发现了一个似乎是造成这种行为的错误。应该会在45版本解决,但在那之前,我们必须带头。

即使该错误似乎仅与 Ipv6 相关,但我在使用 127.0.0.1 时也遇到了同样的问题。然而,有了 Firefox 开发者版 (V 45),这个问题似乎已经解决了。

为什么 Firefox 会关闭连接?

不应该。参考:https://bugzilla.mozilla.org/show_bug.cgi?id=1240319

如何解决?

除了每 3-4 秒发送一次数据以保持连接打开,我不知道。

【讨论】:

  • 非常感谢您花时间提交有关此问题的 Firefox 错误,并在此处提供指向它的链接。
  • @sideshowbarker:很遗憾,我不参与这次 Firefox 改进。
  • 是的,我明白了——我只是想感谢您实际提交了一个关于它的浏览器错误。许多开发人员从不花时间向浏览器项目报告错误——即使他们确实提出了错误,也不总是费心将错误链接发布到任何相关的 Stack Overflow 问题。
【解决方案2】:

听起来很像垃圾回收。

我看到你尝试过超时。但我不确定我是否理解您的结论:为超时设置回调不会触发。

请绝对确定您遵守以下规则:

4.2 垃圾回收

如果 XMLHttpRequest 对象的状态是打开并设置了 send() 标志、接收到标头或正在加载,则不得对 XMLHttpRequest 对象进行垃圾收集,并且它注册了一个或多个事件侦听器,其类型为readystatechange、progress、abort、error、load、timeout 和 loadend 之一。

如果一个 XMLHttpRequest 对象在其连接仍处于打开状态时被垃圾回收,则用户代理必须终止该请求。

xhr.spec.whatwg.org

检查未发送数据时设置了哪些状态、send() 标志和事件侦听器。

【讨论】:

  • 感谢您的精彩回答!不幸的是,这不是问题:即使示例可以得出这个结论,将请求保存在全局变量中也没有任何区别。此外,最终事件提供了一个正确的对象。
  • 赏金是给你的,所以至少有人使用这些积分。感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多