长轮询xmlhttprequest和间歇性网络连接的问题
Issues with long polling XMLHttpRequests and intermittent network connections
我已经实现了一个长轮询连接,允许我使用Tomcat web服务器和前端的标准javascript进行服务器端推送(comet)。为了保持连接继续,我有一个简单的keep-alive循环,当最后一个请求完成/失败时,它就会启动一个新的请求。
绝大多数时候,这种连接工作得很好,并且像我期望的那样保持活跃。但是,我注意到,当用户的互联网连接断开时(例如,他们从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);
这似乎是一个相当标准的情况,但我还没有看到任何关于如何允许长轮询连接从这种断开中恢复的对话。
我做错了什么吗?是否有其他更标准的方法来做长轮询/彗星来规避这个问题?
对此有任何帮助将不胜感激。由于
我认为处理这个问题的最好方法是将长轮询请求的持续时间限制在一定时间内,T
(例如60秒是一个不合理的值),然后在客户端使用超时来检测停滞状态。理想情况下,您可以使用XHR timeout
属性来实现此功能,但它不支持x-browser,尽管它在W3C规范中。因此,您将希望使用setTimeout
和xhr.abort()
实现您自己的支持。
客户端可以假设,如果他们在T秒内没有得到响应,则连接已经停止,并且应该中止当前请求并尝试重新连接。
这工作得相当好,但确实意味着在检测客户端连接何时停止(最多T秒)时会有一些延迟。对于长期的民意调查请求,我不知道还有多少事情要做。如果你真的需要一个更好的解决方案,那么你可能想看看一个流彗星连接,它发送回心跳消息或WebSockets。
这是一个简单的答案。不幸的是,这是一个不平凡的问题,有各种奇怪的边缘情况。例如,您可能关心(也可能不关心)具有连接超时的代理服务器,或者在用户计算机上更改默认TCP超时的各种方式。这就是为什么我们看到了像Socket这样的框架。隐藏了很多丑陋的东西。
注:可能值得注意的是,您可以通过navigator.onLine
在某些浏览器中监视在线状态,但它的支持很差。它唯一能正常运行的浏览器是Chrome。它真正告诉您的唯一事情是,如果已知用户由于某种原因处于离线状态。它不能告诉你它们有工作连接。
解决方案是启用TCP keepalive。它是TCP中的一种机制,用于在失去可达性时关闭连接。您的应用程序不需要修改。可以在O/S或服务器应用程序中启用keepalive。
至少在我的用例中,它只能通过组合setTimeout和clearTimeout:
function longPoll() {
xhttp.open("GET", apiUrl, true);
xhttp.send();
const tryAgain = setTimeout(() => {
xhttp.abort;
longPoll();
}, 101000);
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4) {
if(xhttp.status == 200) {
clearTimeout(tryAgain);
//do stuff
longPoll();
}
}
}
基本上,您计划在建立连接的同时重试。当您获得响应时,重试将被取消。如果没有得到响应,则重试不会被取消,而是在设置的超时之后进行。这再次计划在重试,等等。直到收到响应并取消最近计划的重试为止。
- 节点不是持久的网络连接
- 检测与流星的3G网络连接
- 如何通过AJAX调用检查网络连接
- 在 JavaScript 中检查网络连接
- 节点.js mysql 查询和网络连接
- 科尔多瓦 IOS 8.1 打开应用程序时如何检查网络连接
- 检查网络连接已连接/已断开
- 使用IONIC的IOS没有网络连接功能问题
- 断开网络连接时出现消息(SamsungSmart电视应用程序)
- 正在检查Cordova和AngularJS中的网络连接状态
- AngularJS/Cordova应用程序中网络连接断开时显示弹出窗口
- 检查javascript中是否存在网络连接
- 什么'当你'I’我失去了网络连接
- 通过Firefox扩展检查网络连接
- 使用ngCordova检查活跃的网络连接,如果在ionic中不是活跃的,就退出应用
- 如何仅在有网络连接的情况下更新屏幕/网站
- 等到网络连接后再启动节点webkit应用
- jQuery.Get将请求排队,直到网络连接可用
- 如何根据网络连接的可用性切换基础层
- 如何根据网络连接的可用性切换基础层