Короткий ответ: WebSocket нужно организовать как отдельный realtime-слой, а не как хаотичные new WebSocket() по всему проекту. HTTP оставьте для обычных запросов, форм, загрузки данных и авторизации. WebSocket используйте для событий: уведомлений, прогресса, чата, live-статусов и обновлений
Разделите роли HTTP и WebSocket
Хорошая схема:
HTTP: login, профиль, настройки, формы, история
WebSocket: новые события, прогресс, уведомления, live-изменения
Не нужно переносить все API в WebSocket. Это усложнит отладку и сломает привычную модель запрос-ответ
Единый формат сообщений
{
"type": "notification",
"requestId": "abc-123",
"payload": {
"text": "Новый заказ"
}
}
type помогает маршрутизировать событие. requestId нужен для request-response поверх WebSocket. payload хранит данные
Менеджер соединения
На клиенте сделайте один слой:
class RealtimeClient {
constructor(url) {
this.url = url;
this.socket = null;
}
connect() {
this.socket = new WebSocket(this.url);
this.socket.onmessage = (event) => this.handleMessage(event);
}
send(type, payload) {
if (this.socket?.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify({ type, payload }));
}
}
handleMessage(event) {
const message = JSON.parse(event.data);
console.log(message.type);
}
}
Компоненты интерфейса не должны сами знать все детали подключения
Reconnect
Добавьте переподключение с задержкой, но не делайте бесконечный агрессивный цикл. Хорошо:
1s -> 2s -> 4s -> 8s -> max 30s
После logout reconnect нужно отключать, иначе приложение снова откроет соединение уже после выхода пользователя
Авторизация
Авторизация может быть через cookie, токен или первое auth-сообщение. Важно не считать WebSocket публичным. Если событие содержит личные данные, сервер должен проверить пользователя и права
Мониторинг
Логируйте:
- количество подключений;
- ошибки подключения;
- close codes;
- размер сообщений;
- частоту reconnect;
- задержку доставки.
Без этого сложно понять, почему realtime “иногда не работает”
Синхронизация после reconnect
После переподключения клиент не должен просто “ждать новые события”. Он мог пропустить часть сообщений. Поэтому добавьте восстановление состояния:
close -> reconnect -> HTTP fetch current state -> subscribe again
Например, чат после reconnect должен загрузить последние сообщения, а дашборд — актуальные значения. WebSocket приносит новые события, но не обязан хранить историю
Версионирование сообщений
Если проект развивается, добавьте версию протокола:
{
"version": 1,
"type": "notification",
"payload": {}
}
Это поможет плавно обновлять frontend и backend, особенно если клиенты могут работать на старой версии приложения
Документируйте события
Сделайте маленькую таблицу событий:
type кто отправляет payload
notification server text, level
chat_message client/server roomId, text
progress_update server taskId, percent
Такая таблица снижает хаос: frontend и backend одинаково понимают, какие сообщения существуют и какие поля обязательны
Частые ошибки
Первая ошибка — создавать сокет в каждом компоненте
Вторая ошибка — не закрывать соединение при logout
Третья ошибка — не иметь единого формата сообщений
Четвертая ошибка — не делать fallback-синхронизацию через HTTP после reconnect
Пятая ошибка — доверять всем входящим сообщениям без валидации
Шестая ошибка — не иметь плана на пропущенные события. Любой realtime-канал может оборваться, поэтому должна быть обычная синхронизация состояния
Самопроверка
Опишите список событий вашего проекта: что идет через HTTP, что через WebSocket. Затем создайте единый формат сообщения и тестовый клиент. Если каждый компонент открывает свой сокет, архитектуру нужно упрощать
Что почитать дальше по WebSocket
Если нужен общий маршрут по теме, откройте рубрику WebSocket. Для соседних задач пригодятся эти разборы:
- Django: как подружить Celery с WebSocket
- Django: как сохранить биржевые данные, полученные по WebSocket
- FastAPI WebSocket: уведомления в браузер
- Fedora 43: как установить WebSocket сервер



