长轮询XMLHttpRequests和间歇性网络连接的问题

时间:2013-01-07 23:34:19

标签: javascript xmlhttprequest comet

我已经实现了一个长轮询连接,允许我使用Tomcat Web服务器和前端的标准javascript进行服务器端推送(彗星)。为了保持连接,我有一个简单的保持活动循环,一旦最后一个完成/失败就会启动一个新的请求。

绝大多数时候,这种连接完全正常,并且像我期望的那样保持活力。但是,我注意到当用户的互联网连接断开时(例如,他们断开VPN连接,拔掉他们的以太网等)并且我有一个未决的XMLHttpRequest输出到服务器,我没有得到任何失败的迹象。因此,连接无声地死亡,我不知道它发生了,除非我经常向服务器发送请求以测试连接(这似乎违背了使用长轮询的目的)。

这是我在Chrome中看到的请求对象,当它死于这个沉默的死亡时:

request: XMLHttpRequest
    onabort: function ()
    onerror: function ()
    onload: null
    onloadend: null
    onloadstart: null
    onprogress: null
    onreadystatechange: function ()
    readyState: 1
    response: ""
    responseText: ""
    responseType: ""
    responseXML: null
    status: [Exception: DOMException]
    statusText: [Exception: DOMException]
    upload: XMLHttpRequestUpload
    withCredentials: false

我有三个监听器(onabort,onerror,onreadystatechange)设置来警告消息,如果它们被解雇,但每当我连接到服务器时,我什么也得不到。以下是我正在形成请求的方式:

var request = new XMLHttpRequest();

//url is just the url to my servlet to handle this
request.open("GET", url, true);

//handlestatechange is just my standard handling code 
//that I've put an alert at the top of
request.onreadystatechange = handleStateChange;

request.onerror = function()
{
    alert("We encountered an error");
}

request.onabort = function()
{
    alert("I've had an abortion");
}

request.send(null);

这似乎是一个相当标准的情况,但我没有看到任何关于如何允许长轮询连接从这种断开连接恢复的对话。

我做错了吗?有没有其他更标准的方法来做长轮询/彗星来解决这个问题?

对此有任何帮助将不胜感激, 感谢

2 个答案:

答案 0 :(得分:2)

我认为处理此问题的最佳方法是将长轮询请求的持续时间限制为T(例如60秒是一个不合理的值),然后在客户端使用超时检测陷入停滞的状态。理想情况下,您使用XHR timeout属性,但it isn't supported x-browser,尽管属于W3C规范。因此,您需要使用setTimeoutxhr.abort()实现自己的支持。

客户端可以假设如果他们没有在T秒内得到响应,则连接已经停止,并且适合中止当前请求并尝试重新连接。

这种方法运行得相当不错,但确实意味着检测客户端连接何时停止(最多T秒)会有一些延迟。对于长轮询请求,我不知道还有很多工作要做。如果您确实需要更好的解决方案,那么您可能需要查看发回心跳消息或streaming cometWebSockets连接。

这是一个简单的答案。不幸的是,这对于各种奇怪的边缘情况来说都是一个非常重要的问题。例如,您可能会或可能不关心具有连接超时的代理服务器,或者可能在用户计算机上更改默认TCP超时的各种方式。这就是为什么我们看到像Socket.IO这样的框架出现了隐藏很多这种丑陋的原因。

P.S。值得注意的是,您可以通过navigator.onLine监控某些浏览器中的在线状态,但它是poorly supported。唯一真正表现良好的浏览器是Chrome。它真正告诉你的唯一一件事是,由于某些原因,用户是否已知离线。它不能告诉你他们有一个有效的联系。

答案 1 :(得分:0)

解决方案是启用TCP Keepalive。这是TCP中的一种机制,可以关闭连接,从而降低可达性。您的应用程序不需要修改。您可以在O / S或服务器应用程序中启用Keepalive。