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


127

Я граю з HTML5 WebSockets. Мені було цікаво, як витончено закрити зв’язок? Як, що станеться, якщо користувач оновить сторінку або просто закриє браузер?

Існує дивна поведінка, коли користувач просто оновлює сторінку, не викликаючи дзвінки websocket.close()- коли вони повернуться після оновлення, це вплине на websocket.oncloseподію.

Відповіді:


110

Відповідно до специфікації протоколу v76 (яка версія, яку браузер із поточною підтримкою реалізує):

Для чистого закриття з’єднання від одного однорангового повідомлення надсилається кадр, що складається лише з байта 0xFF з наступним байтом 0x00, щоб попросити, щоб інший одноранговий закрив з'єднання.

Якщо ви пишете сервер, вам слід обов’язково надіслати закритий кадр, коли сервер закриває клієнтське з'єднання. Звичайний метод закриття TCP-розетки іноді може бути повільним, а додатки вважають, що з'єднання все ще відкрите, навіть коли його немає.

Веб-переглядач дійсно повинен це зробити для вас, коли ви закриваєте або перезавантажуєте сторінку. Однак ви можете переконатися, що закритий кадр надісланий, зробивши захоплення події перед завантаженням:

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

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


2
Можливо, що у Firefox це з'єднання, здається, зависає під час завантаження наступної сторінки. Я не можу знайти посилання, але я думаю, що в цьому могла помилка. Інша можливість полягає в тому, що oncloseподія запускається несподівано або, можливо, спеціально, коли користувач пересувається / перезавантажується сторінка. Я розмістив запитання із запитанням, якою має бути очікувана поведінка, який браузер має право та як ми реалізуємо автоматичне відновлення.
легетер

4
розгляньте ці проблеми з onbeforeunloadподією
artkoenig


35

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

Стара версія протоколу використовується Opera і iPod / iPad / iPhones, тому дуже важливо, щоб сумісність була реалізована на серверах WebSockets. За допомогою цих браузерів, використовуючи старий протокол, я виявив, що оновлення сторінки або відхід від сторінки чи закриття браузера - це призводить до того, що браузер автоматично закриває з'єднання. Чудово !!

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


4
практичний приклад на стороні сервера, як керувати цим пакетом Hybi?
albanx

9
Здається божевільним, що він не закриває зв’язок. Змінна WebSocket видаляється при перезавантаженні сторінки, тож чому б з'єднання залишалося відкритим, якщо до нього не можна отримати доступ? Повторне використання зв'язку теж не мало б сенсу.
Трайнко

@albanx перевіри мою відповідь нижче
artkoenig

Будь-які зразки коду про те, як надіслати закритий кадр з клієнта веб-сокета (тобто браузера). Я використовую модуль ws npm
Shaik Syed Ali

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.