stompjs xhr_streaming超时

时间:2017-02-26 03:17:38

标签: javascript angularjs websocket spring-websocket stompjs

我在angular(1.5.x)中使用SockJS + stomp客户端来建立带有spring(mvc)服务器的websocket。除此之外一切正常:如果我终止服务器,stomp客户端最多需要两分钟才能检测到浏览器上的连接错误。有没有办法管理一个更短(或立即)的超时或一旦服务器死亡或断开连接抛出事件?

function socketService($rootScope, $q, $log, $timeout, URL) {
    var listener = $q.defer(),
        socket = {
        client: null,
        stomp: null
    };

    var reconnect = function() {
        $log.info('Reconnecting');
        $timeout(function() {
            initialize();
        }, 2000);
    };

    var getMessage = function(data) {
        var message = JSON.parse(data), out = {};
        out.message = message;
        if (message.metadata) {
            out.time = new Date(message.metadata.timestamp);
        }
        $log.info(out);
        return out;
    };

    var startListener = function() {
        $log.info('Connected');
        socket.stomp.subscribe(URL.PROCESS_UPDATES, function(data) {
            listener.notify(getMessage(data.body));
        });

        socket.stomp.subscribe(URL.CONTAINER_UPDATES, function(data) {
            listener.notify(getMessage(data.body));
        });
        $rootScope.$broadcast('web_socket_event', 'CONNECTED');
    };

    var errorCallback = function (error) {
        // Browser gets here 2 minutes after the server is killed. Seems like might be affected by the the xhr_streaming timeout 
        $rootScope.$broadcast('web_socket_event', 'DISCONNECTED');
        reconnect();
    };

    return {
        initialize: initialize,
        receive: receive
    };
    function initialize() {
        var header = {
          'accept-version': 1.1
        };
        $log.info('Connecting');
        // custom header to specify version.
        socket.client = new SockJS(header, URL.ROOT + URL.UPDATES);

        socket.client.debug = function(){};
        socket.stomp.heartbeat.outgoing = 0;
        socket.stomp.heartbeat.incoming = 2000;
        socket.stomp = Stomp.over(socket.client);
        socket.stomp.connect({}, startListener, errorCallback);
        socket.stomp.onerror = errorCallback;
        socket.stomp.onclose = reconnect;
    };

    function receive() {
        return listener.promise;
    };
}


**// browser console:**
Opening Web Socket...
  stomp.js:145 Web Socket Opened...
  stomp.js:145 >>> CONNECT
  accept-version:1.1,1.0
  heart-beat:0,2000

  stomp.js:145 <<< CONNECTED
  version:1.1
  heart-beat:2000,0

  stomp.js:145 connected to server undefined
  stomp.js:145 check PONG every 2000ms

1 个答案:

答案 0 :(得分:2)

我不是WS的专家,但基于我们通过问题评论的对话,以及我对WS的理解,显然你的服务器正在与 NO 心跳进行协商: heart-beat 0,0。第一个0是客户端应该期望没有来自服务器的数据包的最大时间(以毫秒为单位)(当超时时间从服务器发送心跳帧的任何一方都没有通信时),第二个0是等效但从服务器角度看。

您应该将服务器设置为定期发送心跳,并期望客户端发出心跳。这样,您可以让服务器和客户端更好地管理WS连接资源,并确保在应用停滞的连接检测策略或任何其他机制时,“网络”不会断开连接。

我不知道你是如何设置WS服务器的,但下面的示例适用于spring boot中的简单WS服务器:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Component
public class WebSocketConfigurer extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        long heartbeatServer = 10000; // 10 seconds
        long heartbeatClient = 10000; // 10 seconds

        ThreadPoolTaskScheduler ts = new ThreadPoolTaskScheduler();
        ts.setPoolSize(2);
        ts.setThreadNamePrefix("wss-heartbeat-thread-");
        ts.initialize();

        config.enableSimpleBroker("/topic")
                .setHeartbeatValue(new long[]{heartbeatServer, heartbeatClient})
                .setTaskScheduler(ts);
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/my/ws/endpoint")
                .setAllowedOrigins("*")
                .withSockJS();
    }
}