EventSource永久自动重新连接

时间:2014-02-17 14:07:29

标签: javascript server-sent-events server-push

我在项目前端使用JavaScript EventSource。

有时,浏览器与服务器之间的连接失败或服务器崩溃。在这些情况下,EventSource会在3秒后尝试重新连接,如文档中所述。

但它只尝试一次。如果仍然没有连接,则EventSource将停止尝试重新连接,并且用户必须刷新浏览器窗口才能再次连接。

如何防止这种行为?我需要EventSource来尝试永远重新连接,而不仅仅是一次。

浏览器是Firefox。

3 个答案:

答案 0 :(得分:5)

我通过实现保持活动系统来处理这个问题;如果浏览器重新连接我,这一切都很好,但我认为有时它不起作用,而且不同的浏览器可能表现不同。

我在本书的第五章(Blatant plug,在O'Reilly这里找到它:Data Push Applications Using HTML5 SSE)上花了几页,但如果你想要一个不需要任何回复的非常简单的解决方案 - 结束更改,设置一个全局计时器,在30秒之后触发。如果它触发,那么它将终止EventSource对象并创建另一个。最后一个难题是在你的事件监听器中:每次从后端获取数据时,杀死计时器并重新创建它。即只要您至少每30秒获得一次新数据,计时器就永远不会触发。

以下是一些显示此内容的最小代码:

var keepAliveTimer = null;

function gotActivity(){
  if(keepaliveTimer != null)clearTimeout(keepaliveTimer);
  keepaliveTimer = setTimeout(connect, 30 * 1000);
}

function connect(){
  gotActivity();
  var es = new EventSource("/somewhere/");
  es.addEventListener('message', function(e){
    gotActivity();
    },false);
}
...
connect();

另请注意,我在连接之前调用了gotActivity()。否则,在它有机会提供任何数据之前失败或死亡的连接将被忽视。

顺便说一下,如果你也可以改变后端,那么在安静25-30秒之后发送一条空白信息(“心跳”)是值得的。否则前端将不得不假设后端已经死亡。当然,如果您的服务器发送的间隔时间不超过25-30秒,则无需执行任何操作。

如果您的应用程序依赖于Event-Last-Id标头,请认识到您的保持活动系统必须模拟这个;得到更多参与。

答案 1 :(得分:1)

以下,我演示了一种以合理的速率永久地重新连接的方法。

此代码使用防抖功能以及重新连接间隔加倍。在我的测试过程中,它运作良好。它以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();

答案 2 :(得分:0)

根据我的经验,浏览器通常会在出现网络级错误时重新连接,但如果服务器响应HTTP错误(例如状态500)则不会重新连接。

我们的团队制作了一个简单的包装器库,可以在所有情况下重新连接:reconnecting-eventsource。也许有帮助。