Аутентификация и надёжность канала

Как понять, кто подключился, и как держать канал живым и надёжным.

Heartbeat (ping/pong) — периодический обмен служебными фреймами, чтобы убедиться, что соединение живо, и вовремя обнаружить «мёртвые» каналы.

Аутентификация при подключении

WebSocket не имеет привычных HTTP-заголовков на каждом сообщении — авторизуются один раз, при подключении. Обычно клиент передаёт токен. Способы: в query-параметре адреса (wss://host/chat?token=...), в первом сообщении после open, или через cookie (она уходит с рукопожатием). Сервер проверяет токен и либо принимает соединение, либо закрывает его с кодом ошибки.

{ "type": "auth", "token": "eyJhbGciOi..." }

Пока клиент не прошёл аутентификацию, сервер не пускает его в комнаты и игнорирует прочие сообщения.

Heartbeat: жив ли канал

TCP может «тихо умереть»: провод выдернули, Wi-Fi отвалился — а сокет на сервере всё ещё числится открытым. Чтобы это ловить, стороны периодически шлют ping и ждут pong. Не пришёл pong за отведённое время — считаем соединение мёртвым и закрываем.

Сервер  --ping-->  Клиент
Сервер  <--pong--  Клиент   (ок, живой)

Сервер  --ping-->  Клиент
        (pong не пришёл за 30 сек)
Сервер  закрывает «мёртвое» соединение

Переподключение и потеря сообщений

Сети рвутся — клиент обязан переподключаться сам (или через Socket.IO). Правильный реконнект делает паузы с ростом (1с, 2с, 4с...), чтобы не долбить упавший сервер. Отдельная проблема — сообщения, пришедшие во время обрыва: их клиент пропустил. Решение — нумеровать сообщения и при реконнекте просить сервер: «дай всё после №42». Сервер берёт пропущенное из истории (из базы) и досылает.

Как работает под капотом

В протоколе WebSocket есть встроенные ping/pong-фреймы, и многие библиотеки шлют их сами. Но прикладной heartbeat (свой type: "ping") иногда удобнее: он точно проходит через все слои и виден приложению. Восстановление пропущенного опирается на то, что у сообщений есть монотонный номер (или метка времени), а история хранится отдельно от живого канала — поэтому даже после долгого обрыва клиент догоняет состояние.

Частые ошибки

  • Класть токен в код и не проверять его на сервере. Аутентификацию всегда проверяет сервер, клиенту доверять нельзя.
  • Реконнект без задержки и джиттера. Тысячи клиентов разом ударят по поднявшемуся серверу и снова уронят его.
  • Игнорировать пропуски при обрыве. Без нумерации и догрузки часть сообщений потеряется молча.

Итоги

  • WebSocket аутентифицируют один раз при подключении — токеном (query/первое сообщение/cookie).
  • Heartbeat ping/pong обнаруживает «тихо умершие» соединения.
  • Реконнект делают с нарастающей паузой; не штурмуйте упавший сервер.
  • Пропущенные при обрыве сообщения догружают по номеру из истории в базе.
Проверьте себя
1. Когда обычно аутентифицируют WebSocket-клиента?
AВ каждом сообщении заголовком
BОдин раз при подключении — токеном
CТолько после первого сообщения чата
DАутентификация в WebSocket невозможна
2. Зачем нужен heartbeat (ping/pong)?
AЧтобы шифровать данные
BЧтобы обнаружить соединения, которые «тихо умерли»
CЧтобы ускорить рукопожатие
DЧтобы сжимать сообщения
3. Как восстановить сообщения, пропущенные во время обрыва?
AНикак, они потеряны навсегда
BНумеровать сообщения и при реконнекте догрузить всё после последнего номера из истории
CПерезагрузить страницу
DСлать heartbeat чаще