在JavaScript类中,XMLHttpRequest连接到服务器。 服务器正在缓慢地发送数据。这在Chromium中运行良好,但Firefox在随机时间后(大约4s到70s之间)关闭连接。
为何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.
如果服务器每隔几秒钟(<5s)发送一些内容,则连接“永远”保持活动状态。但如果没有发送数据,Firefox会关闭连接。
连接关闭: - readyState = 4 - status = 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);
答案 0 :(得分:3)
进一步搜索后,我在Mozilla中发现了一个Bug,它似乎是这种行为的原因。它应该在版本45中解决,但在那之前,我们必须引导它。
即使这个bug似乎只与Ipv6有关,我也有同样的问题使用127.0.0.1。但是,使用Firefox Developer Edition(V 45),问题似乎已经解决了。
为什么Firefox会关闭连接?
不应该。参考:https://bugzilla.mozilla.org/show_bug.cgi?id=1240319
如何解决?
除了每3-4秒发送一次数据以保持连接打开外,我不知道。
答案 1 :(得分:1)
听起来很像垃圾收集。
我看到你试过超时了。但我不确定我理解你的结论:设置一个超时的回调它不会触发。
绝对确定您遵守这些规则:
4.2垃圾收集
如果XMLHttpRequest对象的状态是通过设置send()标志,收到标头或加载,和打开的,则它不能被垃圾收集,它有一个或多个已注册类型为的事件监听器readystatechange,progress,abort,error,load,timeout和loadend之一。
如果XMLHttpRequest对象在其连接仍处于打开状态时被垃圾收集,则用户代理必须终止该请求。
检查在没有数据发送的情况下设置了哪个状态,send()标志和事件监听器。