ООО «Ивент Хаб» · Москва · работаем по всей России
Пн—Пт, 10:00—19:00hello@gusi-lebedi.comРеквизиты
Практическое руководство

WebSocket: как работает обмен событиями и что происходит при потере связи

Как организовать обмен событиями без ложных подтверждений: постоянное соединение, результат команды, потеря связи и приёмка работы.

Двусторонний обмен сообщениями клиента и сервера через WebSocket

В чате появилась новая реплика, в заявке изменился исполнитель, на экране оператора обновился статус. Пользователь хочет видеть это без постоянного нажатия «Обновить». WebSocket позволяет браузеру и серверу обмениваться сообщениями в обе стороны по открытому соединению. Но выбор протокола ещё не отвечает на вопросы, дошло ли сообщение, выполнена ли команда и что увидит человек после обрыва сети.

В Гуси-Лебеди мы предлагаем разбирать такую задачу через поведение приложения. Ниже рассмотрим условный сервис для обсуждения заявок: два сотрудника работают с одной записью, отправляют сообщения и меняют её состояние. По этому примеру удобно понять, какие требования стоит включить в проект до разработки.

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

Выбор событий для оперативного обновления интерфейса

WebSocket нужен там, где участники обмена должны получать сообщения по мере их появления и отправлять свои, пока соединение открыто. Серверу не приходится ждать очередного запроса браузера, чтобы передать очередное событие. Короткое техническое определение и ограничения браузерного интерфейса приведены в документации MDN.

Перед обменом стороны согласуют подключение. В классической схеме из RFC 6455 клиент отправляет HTTP-запрос с намерением перейти на WebSocket, а сервер при успешном согласовании отвечает 101 Switching Protocols с нужными заголовками. После этого передаются сообщения протокола. Поэтому в диагностике сначала выясняют, установилось ли соединение, и только затем проверяют доставку и обработку событий: это разные этапы.

Представим обсуждение заявки. Сотрудник отправляет комментарий, сервер обрабатывает его и сообщает об обновлении другому участнику. Если второй сотрудник тоже отвечает, обмен продолжается в обратную сторону. Для такого двустороннего разговора WebSocket может быть подходящим вариантом. При этом содержание комментария, состав получателей и порядок обновления экрана задаёт приложение.

Периодический HTTP-опрос решает задачу иначе: браузер сам спрашивает, появились ли изменения. Если обновления редкие, а небольшое ожидание допустимо, этот вариант стоит сравнить с постоянным каналом. Не нужно выбирать WebSocket лишь потому, что он звучит современнее. Сформулируйте, что мешает пользователю сейчас: он пропускает изменения, вручную обновляет страницу или не может продолжить совместную работу.

Мы не советуем писать в требованиях «данные приходят мгновенно». У такого обещания нет проверяемого смысла без условий. Лучше указать, какое изменение должно появиться, кому его показать и как измерить допустимое ожидание в согласованной среде. Сам протокол не отменяет обработку на сервере, сетевые задержки и работу интерфейса.

Ещё одно важное ограничение: обычный браузерный WebSocket API не регулирует автоматически входящий поток по скорости обработки приложения. Если событий слишком много, нельзя просто бесконечно добавлять их в очередь и надеяться, что экран справится. В требованиях полезно разделить события, которые нужно сохранить каждое, и обновления, для которых достаточно последнего состояния. Например, история комментариев и текущий показатель на панели могут требовать разных правил.

Как описывать события и подтверждение результата

Различие действия, события и подтверждённого результата

Самая опасная путаница начинается со слова «отправлено». Пользователь нажал кнопку, браузер вызвал отправку, сервер получил сообщение, запись появилась в базе, другой участник увидел её на экране. Это разные этапы. Если интерфейс рисует галочку уже после первого из них, человек может принять попытку за завершённое действие.

По описанию метода send() данные ставятся в очередь передачи. Вызов метода не является подтверждением сохранения комментария или изменения заявки. Поэтому для нашего примера стоит описать собственное подтверждение операции: какое сообщение возвращает сервер после обработки и как клиент связывает его с отправленной командой.

Рассмотрим предлагаемую последовательность для комментария:

  1. Пользователь нажимает «Отправить». Интерфейс показывает комментарий как ожидающий подтверждения.
  2. Приложение отправляет команду с идентификатором операции. Это предложенное правило конкретного приложения, а не обязательное поле протокола WebSocket.
  3. Сервер проверяет права и данные, выполняет допустимое действие и возвращает результат с тем же идентификатором.
  4. После успешного результата интерфейс меняет отметку на «Сохранено». При отказе объясняет причину, а при неизвестном результате предлагает проверить состояние.

Событие об изменении заявки тоже должно иметь однозначный смысл. «Заявка изменена» недостаточно, если экрану нужно понять, какую строку обновить и какие данные считать актуальными. В контракте приложения можно предусмотреть тип события, идентификатор заявки и версию её состояния. Версия помогает сформулировать правило для устаревшего обновления: например, не заменять новые данные более старым состоянием. Конкретный способ сравнения и обработки нужно согласовать с разработчиками.

Не смешивайте команду «назначить исполнителя» с событием «исполнитель назначен». Первая выражает намерение, второе сообщает о результате. Такой словарь удобно обсуждать вместе с правилами API-интеграции, но внутри постоянного соединения всё равно нужны собственные договорённости о сообщениях, ошибках и подтверждениях.

Как готовить потерю связи и повторное подключение

Потеря соединения и сверка состояния после возвращения

Теперь у первого сотрудника пропала сеть. Второй за это время поменял статус заявки и добавил комментарий. Через некоторое время соединение первого восстановилось. Зелёный индикатор связи появился, но открытая карточка может по-прежнему показывать старые данные. Для пользователя проблема ещё не решена.

Мы предлагаем разделить восстановление канала и восстановление состояния. После подключения приложение должно получить достаточные сведения, чтобы снова показать актуальную заявку. Один возможный вариант: запросить её текущее состояние и свежую историю. Другой: восстановить пропущенные события по сохранённой последовательности. Выбор зависит от устройства сервиса; WebSocket сам не задаёт такую историю и правила её хранения.

До завершения сверки интерфейс должен честно показывать своё состояние. Для нашего сценария подойдёт сообщение «Связь восстановлена, обновляем заявку». Когда данные получены, оно исчезает. Если сверка не удалась, нельзя оставлять отметку «Всё актуально» лишь потому, что канал открыт.

Сложнее ситуация, когда сеть оборвалась сразу после отправки команды. Сервер мог выполнить действие, а подтверждение не дошло до клиента. Предлагать человеку повторить действие вслепую опасно: так можно создать повторный комментарий или повторно выполнить операцию. При проектировании стоит предусмотреть проверку результата по идентификатору и правило обработки повторного обращения. Это требование к приложению, которое нужно отдельно реализовать и испытать.

Повторные попытки подключения тоже должны иметь понятные границы. Запишите, когда приложение пробует снова, когда прекращает попытки и когда просит пользователя войти в аккаунт. Не превращайте истёкшую сессию в бесконечное «Восстанавливаем связь». При разработке веб-сервиса эти состояния лучше включить в сценарии интерфейса сразу, чтобы сообщение об ошибке помогало продолжить работу.

Если после сбоя множество клиентов непрерывно пытаются подключиться одновременно, они могут мешать восстановлению сервера. В разделе RFC 6455 о ненормальном завершении рекомендованы задержка первой попытки и увеличение ожидания при повторных неудачах. Для проекта нужно выбрать и проверить своё правило повторов, а не копировать произвольный интервал из примера кода.

Как принимать обмен через WebSocket

План проверки обновлений, доступа и потери связи

Для приёмки мало открыть две вкладки и увидеть один комментарий. Этот опыт подтверждает только показанное действие в конкретных условиях. Чтобы проверить договорённости, пройдите сценарии с разрывом, восстановлением и ограничениями доступа. Для каждого заранее запишите ожидаемое поведение и сравните его с фактическим.

  • Обычный обмен. Один участник отправляет комментарий. Он получает подтверждение сохранения, а другой видит ровно один новый комментарий в нужной заявке.
  • Изменение во время разрыва. Первый участник теряет связь, второй изменяет заявку. После возвращения первый получает актуальное состояние; старые данные не обозначаются как свежие.
  • Неизвестный результат команды. Соединение прерывается после отправки. Приложение проверяет итог по согласованному правилу и не создаёт повторную операцию без разбора результата.
  • Выход из аккаунта. После завершения сеанса прежний канал не должен продолжать выдавать защищённые данные или принимать действия от вышедшего пользователя.
  • Чужая заявка. Пользователь без доступа не получает её события и не может изменить запись через сообщение в канале.
  • Избыточный поток. На тестовом стенде проверяют согласованные ограничения: приложение не должно бесконтрольно накапливать сообщения и терять управляемость интерфейса.

Для защищённого обмена нужно отдельно проверить WSS, допустимые источники подключения, права на каждое действие и ограничения входящих сообщений. Соединение с сервером само по себе не предоставляет право менять любую заявку. Эти принципы изложены в рекомендациях OWASP по безопасности WebSocket. Проверку доступа нельзя заменять только скрытой кнопкой в интерфейсе.

Полезный результат проектирования в Гуси-Лебеди мы предлагаем оценивать по четырём вопросам: что передаётся, чем подтверждается действие, что происходит при разрыве и как возвращаются актуальные данные. Когда на них есть конкретные ответы, обсуждать реализацию и принимать работу гораздо проще.

Начать проект

Обсудим вашу задачу

Ответим в течение рабочего дня. Можно без технического задания — достаточно цели и вводных.

Заполнить короткий бриф ↗
Навигация по экспертизе

Ещё направления для вашего проекта

Все 86 услуг →