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

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

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

Ответ 1

В соответствии с спецификацией протокола v76 (которая является версией браузера с текущей поддержкой):

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

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

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

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

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

Ответ 2

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

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

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

Ответ 4

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