0% прочитано

Після відновлення WebSocket-з’єднання клієнт повинен звіритися із сервером

Відновлене WebSocket-з’єднання не гарантує, що клієнт отримав усі події під час розриву. Розбираю, чому після повторного підключення варто ще раз отримати канонічний стан із сервера і як це робити без дублювання та стрибків в інтерфейсі.

31 жовтня 2026 р. 9 хв читанняЛаравель

WebSocket добре працює як канал швидкої доставки змін, але саме з’єднання не є гарантією повної історії подій.

Користувач може закрити ноутбук, втратити мережу, перейти між Wi-Fi і мобільним інтернетом або просто мати короткий розрив з’єднання. У цей час сервер продовжує змінювати стан.

Коли клієнт знову під’єднався, статус connected означає лише одне: канал знову доступний. Він не доводить, що між старим і новим з’єднанням нічого не було втрачено.

Після повторного підключення клієнту потрібна не віра в те, що всі події дійшли, а звірка з канонічним станом сервера.

Розрив з’єднання створює невидиме вікно між подіями

Під час розриву серверний стан продовжує змінюватися
12:00:00 connected12:00:05 disconnected 12:00:08 notification created12:00:12 message read12:00:18 another notification created 12:00:25 connected again

У такому сценарії клієнт може не знати про дві нові нотифікації та про зміну стану повідомлення.

Після повторного підключення нові події вже надходитимуть, але пропущений проміжок сам собою не відновиться.

Подія в реальному часі прискорює інтерфейс, але канонічний стан залишається на сервері

Якщо сервер уже зберігає нотифікації, повідомлення, read_at, кількість непрочитаних або інший достовірний стан, саме він повинен бути основою для відновлення клієнта.

WebSocket-подія потрібна для швидкості. Вона дозволяє не чекати наступного HTTP-запиту, коли зміна відбулася прямо зараз.

Але після невідомого проміжку без зв’язку краще знову запитати сервер, ніж намагатися здогадатися, які саме події могли бути пропущені.

Після повторного підключення потрібна окрема операція звірки

Після відновлення каналу клієнт повторно читає серверний стан
echo.connector.pusher.connection.bind(    'connected',    async () => {        await refreshUnreadCount();        await refreshRecentNotifications();    },);

Конкретний код залежить від WebSocket-клієнта й версії бібліотеки, але принцип стабільний: повторне підключення має запускати звірку.

Це може бути один API-запит із компактним знімком стану або кілька невеликих запитів для тих частин інтерфейсу, які справді залежать від оновлень у реальному часі.

Не обов’язково повторно завантажувати всю сторінку

Звірка не повинна перетворюватися на повне перезавантаження застосунку.

Для нотифікацій часто достатньо отримати:

  • актуальну кількість непрочитаних;
  • останні кілька нотифікацій;
  • ідентифікатор або час останньої відомої зміни;
  • за потреби - актуальні стани елементів, які зараз відкриті.

Знімок стану треба поєднувати зі станом клієнта без дублювання

Під час повторного підключення легко отримати одну й ту саму нотифікацію двома шляхами: спочатку через HTTP-запит зі знімком стану, а за мить - через подію в реальному часі.

Тому клієнтський список повинен мати стабільний ідентифікатор і оновлювати елемент за id, а не просто додавати все в кінець масиву.

Одна функція для знімка стану і подій у реальному часі
function upsertNotification(    notification,) {    const index =        notifications.value.findIndex(            (item) =>                item.id === notification.id,        );     if (index === -1) {        notifications.value.unshift(            notification,        );         return;    }

Лічильник краще замінити серверним значенням, а не вгадувати різницю

Після повторного підключення небезпечно робити щось на кшталт "ми, мабуть, пропустили дві події, тому додамо два".

Клієнт не знає, скільки подій було створено, прочитано або видалено під час розриву.

Якщо сервер може повернути unreadCount = 7, клієнт повинен встановити 7, а не намагатися відтворити всі проміжні інкременти.

Для відкритого чату може знадобитися окрема звірка повідомлень

Якщо під час розриву користувач залишався на сторінці конкретного діалогу, після повторного підключення варто перевірити й сам діалог.

Замість повного повторного завантаження історії можна запросити повідомлення після останнього відомого message_id або іншого стабільного курсора.

Це вже не просто "перемалювати UI", а відновити пропущений відрізок історії.

Кожне технічне повторне підключення не повинно запускати шторм HTTP-запитів

Нестабільна мережа може кілька разів поспіль переводити з’єднання між станами disconnected і connected.

Тому звірку варто централізувати, не дублювати в кожному компоненті й за потреби захищати від паралельних повторних запусків.

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

Початкове завантаження і повторне підключення можуть використовувати той самий шлях синхронізації

Один шлях для початкового завантаження і синхронізації після повторного підключення
async function syncNotificationState() {    const state =        await api.getNotificationState();     unreadCount.value =        state.unreadCount;     mergeNotifications(        state.notifications,    );} onMounted(    syncNotificationState,); 

Повернення у вкладку браузера - ще один хороший момент для звірки

Браузер може призупиняти фонову вкладку, мережеві події можуть приходити із затримкою, а WebSocket може бути перепідключений непомітно для конкретного компонента.

Тому для критичних лічильників і нотифікацій корисно мати ще один дешевий тригер: коли вкладка знову стає видимою, перевірити актуальний стан на сервері.

Це особливо добре працює разом із повторним підключенням, а не замість нього.

Що варто перевірити тестами

Мінімальний набір сценаріїв
1. Після узгодження повторного підключення з'являється пропущене сповіщення.2. Кількість непрочитаних повідомлень замінюється значенням сервера.3. Те саме сповіщення зі знімка та реального часу не дублюється.4. Активний потік отримує повідомлення після останнього відомого курсора.5. Кілька подій повторного підключення не запускають перекриваючі запити на синхронізацію.6. Невдале узгодження можна безпечно повторити.7. Узгодження не очищує новіший стан реального часу.8. Повернення до видимої вкладки браузера може оновити застарілі лічильники.9. Початкове завантаження та повторне підключення використовують той самий канонічний шлях синхронізації.10. Події WebSocket продовжують оновлювати інтерфейс користувача після завершення узгодження.

Повторне підключення відновлює канал, але звірка відновлює достовірний стан

Повторне WebSocket-підключення потрібне, щоб клієнт знову почав отримувати нові події.

Але для правильного стану інтерфейсу цього недостатньо. Клієнт повинен перевірити, що сталося під час розриву, через канонічний серверний стан.

Оновлення в реальному часі відповідають за швидкість реакції. Серверна звірка відповідає за відновлення достовірного стану після невідомого проміжку без зв’язку.

Після повторного підключення я довіряю стану не тому, що з’єднання знову зелене, а тому, що клієнт повторно звірився із сервером.