如何确定SSE连接已关闭?

时间:2015-01-07 17:19:09

标签: javascript server-sent-events

我们在javascript中打开了一个SSE连接,由于服务器重启或其他原因,它可能会不时地关闭。在这种情况下,重新建立连接将是一件好事。怎么做?有没有办法在客户端找到连接已关闭?

这里:https://developer.mozilla.org/en-US/docs/Web/API/EventSource我发现只有一种方法可以关闭连接,但没有回调或测试方法来确定连接是否仍然存在。

感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

如果关闭连接(以浏览器可以实现的方式),它将自动连接。而且它很快就会这样做(默认情况下Chrome浏览器为3秒,Firefox为5秒)。 readyState在执行此操作时将是CONNECTING(0)。如果首先连接有问题(例如由于CORS问题),它只会被禁止(2)。一旦关闭,它就不会重试。

我更喜欢在顶部添加保持活动机制,因为浏览器无法始终检测死套接字(更不用说被锁定的远程服务器进程等)。有关详细代码,请参阅使用HTML5 SSE的数据推送应用程序的第5章,但基本上它涉及让服务器每15秒发送一条消息,然后是一个运行20秒的JavaScript计时器,但每次收到消息时都会重置。如果计时器过期,我们关闭连接并重新连接。

答案 1 :(得分:4)

更新-

EventSource 现在具有三个事件处理程序:onerroronmessageonopen。这些应该足以应付客户端所需的一切。

类似这样的东西:

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
}

参考:mozilla.org : EventSource : Event handlers

答案 2 :(得分:1)

检查readyState属性:

var es = new EventSource();

// Сheck that connection is not closed
es.readyState !== 2;
// or
es.readyState !== EventSource.CLOSED;

答案 3 :(得分:1)

最好不要尝试确定连接是否已关闭。我认为没有办法。服务器端事件在所有浏览器中的工作方式都不同,但是在某些情况下它们都会关闭连接。例如,Chrome重新启动服务器时,由于502错误而关闭了连接。因此,最好使用保持活动状态(如其他人建议的那样)或针对每个错误重新连接。保持活动状态仅在指定的时间间隔内重新连接,该间隔必须保持足够长的时间,以免使服务器不堪重负。每次发生错误时重新连接都将延迟降到最低。但是,只有采取使服务器负载最小的方法才有可能。下面,我演示一种以合理的速率重新连接的方法。

此代码使用防抖功能以及重新连接间隔加倍。它工作良好,连接时间为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();