Правильное закрытие WebSocket (HTML5, Javascript)


127

Я играю с HTML5 WebSockets. Мне было интересно, как мне изящно закрыть соединение? Например, что произойдет, если пользователь обновит страницу или просто закроет браузер?

Когда пользователь просто обновляет страницу без вызова, происходит странное поведение websocket.close()- когда они возвращаются после обновления, он попадает в websocket.oncloseсобытие.

Ответы:


111

Согласно спецификации протокола v76 (это версия, которую реализует браузер с текущей поддержкой):

Чтобы правильно закрыть соединение, от одного однорангового узла отправляется кадр, состоящий только из байта 0xFF, за которым следует байт 0x00, чтобы попросить другого однорангового узла закрыть соединение.

Если вы пишете сервер, вы должны убедиться, что отправили закрывающий фрейм, когда сервер закрывает клиентское соединение. Обычный метод закрытия сокета TCP иногда может быть медленным и заставлять приложения думать, что соединение все еще открыто, даже если это не так.

Браузер действительно должен делать это за вас, когда вы закрываете или перезагружаете страницу. Однако вы можете убедиться, что кадр закрытия отправлен, захватив событие beforeunload:

window.onbeforeunload = function() {
    websocket.onclose = function () {}; // disable onclose handler first
    websocket.close();
};

Я не уверен, как можно получить событие onclose после обновления страницы. Объект websocket (с обработчиком onclose) больше не будет существовать после перезагрузки страницы. Если вы немедленно пытаетесь установить соединение WebSocket на своей странице при загрузке страницы, то вы можете столкнуться с проблемой, когда сервер отказывает в новом соединении сразу после того, как старое отключилось (или браузер не готов. для установления соединений в точке, в которой вы пытаетесь подключиться), и вы получаете событие onclose для нового объекта websocket.


2
Возможно, что в Firefox соединение зависает при загрузке следующей страницы. Я не могу найти ссылку, но думаю, что здесь была ошибка. Другая возможность заключается в том, что oncloseсобытие запускается неожиданно или, возможно, специально, когда пользователь перемещается / страница перезагружается. Я разместил вопрос о том, каким должно быть ожидаемое поведение, в каком браузере оно работает правильно и как мы реализуем автоматическое переподключение.
leggetter

4
рассмотрите эти проблемы с onbeforeunloadивентом
artkoenig


35

Дело в том, что сегодня используются 2 основные версии протокола WebSockets. Старая версия, в которой используется [0x00][message][0xFF]протокол, а есть новая версия, использующая пакеты в формате Hybi .

Старая версия протокола используется Opera и iPod / iPad / iPhones, поэтому на самом деле важно, чтобы на серверах WebSockets была реализована обратная совместимость. В этих браузерах, использующих старый протокол, я обнаружил, что обновление страницы, уход со страницы или закрытие браузера - все это приводит к тому, что браузер автоматически закрывает соединение. Большой!!

Однако в браузерах, использующих новую версию протокола (например, Firefox, Chrome и, в конечном итоге, IE10), только закрытие браузера приведет к автоматическому закрытию соединения браузером. То есть, если вы обновляете страницу или уходите со страницы, браузер НЕ закрывает соединение автоматически. Однако браузер отправляет на сервер гибридный пакет с первым байтом (протоидентификатором) 0x88(более известным как закрытый фрейм данных). Как только сервер получит этот пакет, он может принудительно закрыть само соединение, если вы того пожелаете.


4
практический пример на стороне сервера, как управлять этим пакетом hybi?
albanx 09

9
Кажется безумием, что он не закрывает соединение. Переменная WebSocket стирается при перезагрузке страницы, так почему же соединение остается открытым, если к нему нет доступа? Повторное использование соединения тоже не имело бы смысла.
Трийнко 09

@albanx проверьте мой ответ ниже
artkoenig

Любые примеры кода о том, как отправить закрывающий кадр из клиента websocket (например, браузера). Я использую модуль ws npm
Шайк Сайед Али

3

Как упоминалось theoobe , некоторые браузеры не закрывают веб-узлы автоматически. Не пытайтесь обрабатывать какие-либо события «закрытия окна браузера» на стороне клиента. В настоящее время нет надежного способа сделать это, если учесть поддержку основных настольных И мобильных браузеров (например onbeforeunload, не будет работать в Mobile Safari). У меня был хороший опыт решения этой проблемы на стороне сервера. Например, если вы используете Java EE, взгляните на javax.websocket.Endpoint , в зависимости от браузера, OnCloseметод или OnErrorметод будет вызываться, если вы закроете / перезагрузите окно браузера.


1
В моем случае соединение закрывается во время передачи данных, это хорошо работает в случае браузеров семейства Opera и iOS. Пожалуйста, помогите мне .. Я борюсь с этой проблемой последние две недели. stackoverflow.com/q/30799814/2225439
Mrug

2

Используя метод закрытия веб-сокета, где вы можете написать любую функцию в соответствии с требованиями.

var connection = new WebSocket('ws://127.0.0.1:1337');
    connection.onclose = () => {
            console.log('Web Socket Connection Closed');
        };
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.