stompjs тайм-аут xhr_streaming

Я использую клиент SockJS + stomp в angular (1.5.x), чтобы установить веб-сокет с сервером spring (mvc). Все работает нормально, за исключением этого: если я убью сервер, клиенту 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

person user2994871    schedule 26.02.2017    source источник
comment
Можете ли вы опубликовать код javascript, используемый для создания соединения, вы подписываетесь на функцию обратного вызова на событие ошибки соединения?   -  person artemisian    schedule 26.02.2017
comment
@artemisian, пожалуйста, смотрите код выше, спасибо!   -  person user2994871    schedule 26.02.2017
comment
Пожалуйста, добавьте socket.client.debug = function(msg){ console.log(msg)}; и проверьте согласование пульса (выполните поиск пульса в консоли)? также, если какое-либо сообщение печатается, когда сервер отключается   -  person artemisian    schedule 26.02.2017
comment
@artemisian Я добавил это, но он никогда не вызывается. Через две минуты после убийства сервера я получаю сообщение «Упс! Потеряно соединение с localhost... информационное сообщение консоли браузера, которое вызывается stompjs:145:108.   -  person user2994871    schedule 26.02.2017
comment
как насчет переговоров о прослушивании. проверьте свои инструменты разработчика на сетевой панели в кадрах подключения ws   -  person artemisian    schedule 26.02.2017
comment
в хроме я получаю (код операции - 1) примерно через минуту после установления первоначального соединения. На консоли я закрываю соединение до ошибки ответа на рукопожатие. Сразу после отключения сервера ничего не появляется в кадре WS. Я получаю то же самое (код операции -1) после 15:23:06.322 с длиной 55.   -  person user2994871    schedule 26.02.2017
comment
Как только соединение будет установлено, вы должны увидеть рамку, похожую на a["CONNECTED\nversion:1.1\nheart-beat:0,20000\n\n\u0000"].   -  person artemisian    schedule 26.02.2017
comment
@artemisian Я получаю CONNECT accept version: 1.1, 1.0 Heart-beat: 10000, 10000, за которым следует CONNECTED version 1.1 Heart-beat 0,0 после установления соединения. Я также использую соединение grunt-proxy с livereload, которое выдает ECONNREFUSED, как только сервер убит.   -  person user2994871    schedule 26.02.2017
comment
я добавлю ответ   -  person artemisian    schedule 26.02.2017
comment
Я добавил свой ответ. Надеюсь, это сработает для вас!   -  person artemisian    schedule 26.02.2017
comment
@artemisian, спасибо! Да, похоже, я не посылаю сердцебиение. Будет проведен соответствующий рефакторинг.   -  person user2994871    schedule 27.02.2017


Ответы (1)


Я не эксперт в WS, но на основе нашего разговора в комментариях к вопросу и моего понимания WS ясно, что ваш сервер согласовывает соединение с НИКАКИМ сердцебиением: heart-beat 0,0. Первый 0 — это максимальное время (в миллисекундах), в течение которого клиент вообще не должен ожидать пакетов от сервера (когда этот тайм-аут истекает без связи с какой-либо из сторон, сервер должен отправить кадр пульса), 2-й 0 — это эквивалентно, но с точки зрения сервера.

Вы должны настроить свой сервер так, чтобы он периодически отправлял пульс, а также ожидал пульс от клиента. Таким образом, вы позволяете своему серверу и клиенту лучше управлять ресурсами соединения WS, а также гарантируете, что соединение не будет отключено «сетью» при применении политик обнаружения зависших соединений или любым другим механизмом.

Я не знаю, как вы настроили свой сервер WS, но приведенный ниже пример относится к простому серверу 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();
    }
}
person artemisian    schedule 26.02.2017
comment
Итак, чтобы настроить клиента на ожидание сердцебиения, я могу это сделать через stompJS/SockJS или это должно быть через угловой http-протокол? - person user2994871; 27.02.2017
comment
Клиент отправляет предложение пульса, но последнее слово по условиям согласования пульса остается за сервером. Так же как и ваша весенняя конфигурация, которая будет устанавливать время сердцебиения - person artemisian; 27.02.2017
comment
Итак, у меня есть все, что связано с сердцебиением, и оно работает; однако в консоли браузера (Safari Technology Preview) я могу получить следующую ошибку: «Несовместимый SockJS! Основной сайт использует: 1.1.2, iframe: 1.0.0 '. В ff/Chrome ошибка: «соединение с веб-сокетом закрыто до ответа на рукопожатие..». Эта ошибка носит периодический характер. Есть идеи? - person user2994871; 03.03.2017
comment
Похоже на проблему с версией вашего клиента/сервера sockjs, проверьте журналы отладки в своем браузере. На том же этапе согласования прослушивания также согласовывается версия, ваш клиент сообщает серверу, какую версию он принимает accept-version:1.1,1.0, а затем сервер отвечает, какую из них использовать version:1.1. Убедитесь, что сервер отвечает одной из версий, предложенных клиентом. - person artemisian; 03.03.2017
comment
Совместите свои версии - person artemisian; 03.03.2017
comment
Я обновил приведенный выше код с помощью консоли браузера. Я использую websocket:simple-broker, чтобы указать сердцебиение в app-context.xml следующим образом: сердцебиение=2000, 0. Вы говорите, что мне также нужно указать версию? - person user2994871; 03.03.2017
comment
Нет, похоже, ваше клиентское приложение (внешний интерфейс) использует версию библиотеки javascript sock.js, которая несовместима с версией sock.js, на которой работает сервер, поэтому в некоторых сценариях они не могут взаимодействовать. Один из способов проверить версию, которую использует сервер, — просмотреть логи в браузере. В конечном итоге вам нужно убедиться, что версия sock.js, которую использует клиент, совпадает с версией, которую использует сервер. Скорее всего, вам нужно изменить версию sock.js в клиентском приложении. - person artemisian; 03.03.2017
comment
Я пробовал 1.0.0, 1.1.1 и в настоящее время использую последнюю версию 1.1.2. Я получаю ту же ошибку 1.1.x. SockJS 1.0.0, похоже, имеет следующую ошибку, которая была устранена в версии 1.1.x: github .com/sockjs/sockjs-client/issues/237, с которым я столкнулся, когда пробовал эту версию. - person user2994871; 03.03.2017
comment
какую весеннюю версию вы используете? - person artemisian; 03.03.2017
comment
‹весенняя.версия›4.2.7.РЕЛИЗ‹/весенняя.версия› - person user2994871; 03.03.2017
comment
Давайте продолжим обсуждение в чате. - person artemisian; 03.03.2017
comment
еще одна возможная причина «Несовместимый SockJS!» сообщение об ошибке описано здесь: stackoverflow.com/questions/41951006/ - person stefan.m; 27.04.2017