Должен ли WebSocket.onclose запускаться с помощью навигации пользователя или обновления?
Часть 1: Ожидаемое поведение?
Я вижу некорректное поведение браузера между Firefox и Chrome по отношению к обработчику onclose
.
Кажется, что Chrome не запускает onclose
, если он был вызван навигацией/обновлением пользовательской страницы. Однако Firefox запускает onclose
.
Мне кажется, что Firefox может вести себя корректно здесь:
Когда соединение WebSocket закрывается, возможно, чистое, пользовательский агент должен создать событие, которое использует интерфейс CloseEvent, с закрытым именем события, которое не пузырится, не имеет действия по умолчанию, чей атрибут isClean установите true, если соединение закрыто чисто и false в противном случае, чей атрибут кода установлен в код закрытия соединения с WebSocket, а атрибут причины которого установлен на причину закрытия соединения с WebSocket; и поставить очередь задачи, чтобы сначала изменить значение атрибута readyState на CLOSED (3), а затем отправить событие в объект WebSocket.
Источник: http://www.w3.org/TR/2011/WD-websockets-20110419/#closeWebSocket
Даже если это может привести к некоторому скрытому коду/неожиданному поведению.
Кто-нибудь может подтвердить ожидаемое поведение?
Часть 2: Как реализовать автоматическое повторное подключение?
Если у вас есть библиотека, которая автоматически настраивается для пользователя, как вы знаете, следует ли пытаться восстановить соединение? Вы проверяете свойство CloseEvent.wasClean
? Я должен предположить, что "чистый" означает, что закрытие должно было произойти через вызов API на WebSocket.close()
или сервер, отправляющий закрытый кадр? Если ошибка сети вызывает закрытие, я предполагаю, что wasClean
будет false
?
В библиотеке JavaScript Pusher мы предположили (onclose → waiting → connection), что закрытие должно инициировать повторное подключение, если мы не находимся в закрытом состоянии - разработчик решил закрыть соединение. Похоже, что клиентская библиотека socket.io делает то же самое.
На основе этого события Firefox onclose, вызванного пользовательской навигацией/обновлением, запускает нежелательное повторное соединение, потому что ни одна из библиотек не проверяет свойство CloseEvent.wasClean
.
Пример и видео
Вот пример, который вы можете использовать для демонстрации несогласованности:
http://jsbin.com/awonod/7
Здесь видео меня демонстрирует проблему:
http://www.screenr.com/vHn8
(поздно, проигнорируйте пару промахов:))
Следует отметить, что мое нажатие клавиши Escape также может привести к закрытию соединения WebSocket. Однако, если вы внимательно посмотрите или попробуете сами, вы увидите, что событие закрытия регистрируется непосредственно перед обновлением страницы.
Ответы
Ответ 1
Неожиданное поведение связано с тем, как Firefox и Chrome обрабатывают закрытие Websocket. Когда страница обновляется, оба браузера закрывают соединение, однако Firefox выполнит ваш код на закрытии, а Chrome завершает соединение и пропускает прямо, чтобы перезагрузить новую страницу. Так что да, я подтверждаю это странное поведение.
Еще более странным является тот факт, что, по моим наблюдениям, вызов websocket.close() в chrome немедленно закроет соединение и вызовет функцию onclose, в то время как Firefox ждет сообщения с сервера.
Свойство wasClean будет истинным, если с сервера было получено сообщение о закрытии
Если ваша библиотека автоматически подключается без проверки свойства wasClean, это может вызвать проблему, поскольку она пытается восстановить соединение при обновлении страницы. Вы должны не использовать библиотеку для этого и делать это вручную, это не должно быть очень сложно, просто вызовите connect в функции onclose с инструкцией if, убедившись, что свойство onclean истинно. Или еще более безопасно установить переменную в onbeforeunload, которая предотвращает любое новое соединение.
надеюсь, что это поможет!
Ответ 2
У меня есть несколько слов для добавления,
Когда вы обновляете страницу, вызывается событие "onclose", и большинство браузеров работают синхронно, если браузер работает асинхронно, тогда только он не будет закрыт.
Здесь синхронные средства подключаются по мере необходимости (обновление/навигация).
Асинхронные средства всегда связаны. так что придется использовать webSocket. всегда открывать.
https://developer.mozilla.org/@api/deki/files/6227/=AsyncUnload.jpg
Ссылка закрытого события Сеть Mozilla
Web Socket
Здесь вы также найдете ответ на "wasClean", т.е. полностью закрыт.
Надеюсь, это скомпрометирует.