我们在javascript中打开了一个SSE连接,由于服务器重启或其他原因,它可能会不时地关闭。在这种情况下,重新建立连接将是一件好事。怎么做?有没有办法在客户端找到连接已关闭?
在这里:https://developer.mozilla.org/en-US/docs/Web/API/EventSource我发现只有一种方法可以关闭连接,但没有回调或测试方法来确定连接是否仍然存在。
谢谢您的帮助。
如果连接已关闭(以浏览器可以实现的方式),它将自动连接。而且它很快就会这样做(默认情况下Chrome浏览器为3秒,Firefox为5秒)。 readyState
将在这样做时连接(0)。如果首先连接有问题(例如由于CORS问题),它只会被禁止(2)。 CLOSED后,它不会重试。
我更喜欢在顶部添加保持活动机制,因为浏览器无法始终检测死套接字(更不用说被锁定的远程服务器进程等)。有关详细代码,请参阅使用HTML5 SSE的数据推送应用程序的第5章,但基本上它涉及让服务器每15秒发送一条消息,然后是一个运行20秒的JavaScript计时器,但每次收到消息时都会重置。如果计时器到期,我们关闭连接并重新连接。
更新 -
EventSource现在有三个事件处理程序:onerror
,onmessage
和onopen
。这些应该足以处理客户端所需的一切。
像这样的东西:
ssEvent = new EventSource( eventUrl );
ssEvent.onopen = function (evt) {
// handle newly opened connection
}
ssEvent.onerror = function (evt) {
// handle dropped or failed connection
}
ssEvent.onmessage = function (evt) {
// handle new event from server
}
检查readyState
财产:
var es = new EventSource();
// Сheck that connection is not closed
es.readyState !== 2;
// or
es.readyState !== EventSource.CLOSED;
最好不要尝试确定连接是否已关闭。我认为没有办法做到这一点。服务器端事件在所有浏览器中的工作方式不同,但在某些情况下它们都会关闭连接。例如,Chrome会在重新启动服务器时关闭502错误的连接。因此,最好使用keep-alive,因为其他人建议或重新连接每个错误。保持活动只在指定的时间间隔重新连接,必须保持足够长的时间以避免压倒服务器。重新连接每个错误的延迟可能性最小。但是,只有采用将服务器负载降至最低的方法才有可能。下面,我演示了一种以合理的速率重新连接的方法。
此代码使用去抖功能以及重新连接间隔加倍。它运行良好,在1秒,4,8,16 ......连接,最多64秒,在此时间内以相同的速率重试。我希望这可以帮助一些人。
function isFunction(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
function debounce(func, wait) {
var timeout;
var waitFunc;
return function() {
if (isFunction(wait)) {
waitFunc = wait;
}
else {
waitFunc = function() { return wait };
}
var context = this, args = arguments;
var later = function() {
timeout = null;
func.apply(context, args);
};
clearTimeout(timeout);
timeout = setTimeout(later, waitFunc());
};
}
// reconnectFrequencySeconds doubles every retry
var reconnectFrequencySeconds = 1;
var evtSource;
var reconnectFunc = debounce(function() {
setupEventSource();
// Double every attempt to avoid overwhelming server
reconnectFrequencySeconds *= 2;
// Max out at ~1 minute as a compromise between user experience and server load
if (reconnectFrequencySeconds >= 64) {
reconnectFrequencySeconds = 64;
}
}, function() { return reconnectFrequencySeconds * 1000 });
function setupEventSource() {
evtSource = new EventSource(/* URL here */);
evtSource.onmessage = function(e) {
// Handle even here
};
evtSource.onopen = function(e) {
// Reset reconnect frequency upon successful connection
reconnectFrequencySeconds = 1;
};
evtSource.onerror = function(e) {
evtSource.close();
reconnectFunc();
};
}
setupEventSource();