Протокол сообщений: типы событий на JSON

Договариваемся, в каком формате клиент и сервер обмениваются сообщениями.

Протокол сообщений — соглашение о структуре каждого сообщения: какие поля есть и как по ним понять, что это за событие.

Зачем нужен протокол

По одному каналу ходят разные события: сообщение чата, вход пользователя, набор текста («печатает...»), ошибка. Если слать просто текст, приёмная сторона не разберёт, что это. Поэтому каждое сообщение оборачивают в конверт — JSON-объект с обязательным полем type.

Единый конверт

Договоримся: каждое сообщение — объект с полем type и полезной нагрузкой:

{ "type": "chat", "user": "anna", "text": "привет" }
{ "type": "join", "user": "ivan" }
{ "type": "typing", "user": "anna" }
{ "type": "error", "message": "комната переполнена" }

Получив сообщение, обе стороны смотрят на type и решают, что делать. Это как switch по типу события.

Маршрутизация по типу — чистая логика

Диспетчеризация по полю type — обычная работа с объектами, сервер не нужен. Покажем разбор на чистом JS:

function describe(raw) {
  const msg = JSON.parse(raw);
  switch (msg.type) {
    case "chat":   return msg.user + ": " + msg.text;
    case "join":   return "-> вошёл " + msg.user;
    case "typing": return msg.user + " печатает...";
    default:       return "неизвестно: " + msg.type;
  }
}

console.log(describe('{"type":"join","user":"ivan"}'));
console.log(describe('{"type":"chat","user":"anna","text":"привет"}'));
console.log(describe('{"type":"ping"}'));

Вывод:

-> вошёл ivan
anna: привет
неизвестно: ping

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

WebSocket сам по себе передаёт лишь байты — он не знает про чат, входы и ошибки. Весь смысл задаёт ваш протокол поверх него. Поле type — точка расширения: добавили новое событие — клиенты, которые его не знают, просто попадут в default и проигнорируют, а не сломаются. Поэтому правило: всегда обрабатывайте неизвестный type безопасно.

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

  • Слать разные форматы для разных событий. Единый конверт с type упрощает и клиент, и сервер.
  • Падать на неизвестном type. Разные версии клиента и сервера должны уживаться — неизвестное игнорируйте.
  • Не валидировать входящие данные на сервере. Клиент может прислать что угодно; проверяйте структуру, прежде чем доверять.

Итоги

  • Каждое сообщение — JSON-конверт с обязательным полем type.
  • Обе стороны маршрутизируют обработку по type, как switch.
  • Неизвестные типы игнорируйте безопасно — это даёт совместимость версий.
  • Сервер обязан валидировать входящие данные, не доверяя клиенту.
Проверьте себя
1. Зачем в сообщениях вводят поле type?
AДля шифрования
BЧтобы получатель понимал, что это за событие, и маршрутизировал обработку
CЭто требование протокола WebSocket
DЧтобы уменьшить размер сообщения
2. Как правильно поступить с сообщением неизвестного type?
AЗакрыть соединение
BБросить исключение
CБезопасно проигнорировать
DПереотправить отправителю