В первом модуле мы запомнили: HTTP всегда работает по схеме «клиент спросил — сервер ответил». Сервер сам ничего никому не присылает. Это удобно в большинстве случаев — но не во всех.
Чат, где сообщение собеседника должно появиться у вас сразу. Биржевые котировки, которые обновляются десять раз в секунду. Push-уведомления, не привязанные к действию пользователя. Многопользовательская игра, где состояние мира меняется по решениям других игроков. Здесь REST не подходит: клиент не может постоянно дёргать сервер «а что нового, а что нового, а что нового» по тысяче раз в минуту.
Для таких задач придумали WebSocket.
Аналогия
REST — это переписка по СМС. Каждое сообщение — отдельная штука. Чтобы что-то узнать, надо спросить и подождать ответ. Если друг ничего нового вам не сказал, нужно специально дёргать его «ну как там».
WebSocket — это телефонный звонок. Соединение открыто, оба собеседника слышат друг друга в любой момент. Кто угодно может что-то сказать, и другой тут же это получит. Когда разговор закончен — кладёте трубку.
Как выглядит на стороне фронта
В каждом современном браузере есть встроенный конструктор WebSocket:
const socket = new WebSocket('wss://echo.websocket.org');
socket.addEventListener('open', () => {
console.log('Соединение установлено');
socket.send('Привет, сервер!');
});
socket.addEventListener('message', (event) => {
console.log('Пришло от сервера:', event.data);
});
socket.addEventListener('close', () => {
console.log('Соединение закрыто');
});
socket.addEventListener('error', (err) => {
console.error('Ошибка', err);
});
Различия с fetch:
- Схема URL — ws:// или wss:// (с TLS), не http://.
- Соединение долгоживущее. Открыли один раз — используем долго.
- Сообщения летят в обе стороны. Клиент шлёт через socket.send(); сервер прислал — срабатывает message-событие.
- Нет статус-кодов и заголовков для каждого сообщения. Это уже не HTTP-запросы — это просто текст или бинарные данные.
Что обычно гоняют через WebSocket
- Чаты, мессенджеры. Сообщения от собеседника появляются мгновенно.
- Live-нотификации. «Кто-то лайкнул ваш пост» — без перезагрузки.
- Котировки, биржа, спортивные счёты. Высокая частота обновлений.
- Многопользовательские игры, совместное редактирование — типа Google Docs.
- Стриминг логов или метрик в админках.
Что НЕ гоняют через WebSocket
- Простые CRUD-запросы. Создать пост через WebSocket можно, но это переусложнение — REST короче и понятнее.
- Чтение статичных или редко меняющихся данных. Здесь HTTP-кэширование выигрывает.
- Загрузка и скачивание файлов. WebSocket для бинарных данных умеет, но HTTP с прогрессом, паузой и докачкой проще.
- Запросы, которые удобно кэшировать. WebSocket это не дружит.
Правило: WebSocket нужен, когда сервер должен сам инициировать сообщение клиенту. Если в задаче этого нет — REST лучше.
Сложности, о которых стоит знать
- Авторизация. WebSocket не поддерживает кастомные заголовки от JS. Токен передают либо в query-параметре (с тем же риском, что и в REST — см. 7.2), либо через короткоживущий токен, который выдаётся отдельным REST-запросом перед открытием соединения.
- Reconnect. Соединение может оборваться — смена сети, переход в режим сна, балансировка на сервере. Боевой клиент должен пытаться переподключиться (обычно с экспоненциальным backoff).
- Сообщения теряются при разрыве. WebSocket — just-in-time. Если клиент был оффлайн пять минут, сервер должен где-то хранить пропущенные сообщения и отдать их при реконнекте.
- State sync. Сервер пушит апдейты — клиент должен правильно их применять к локальному состоянию. Может потребоваться периодически синхронизировать всё состояние через REST.
SSE — полу-WebSocket для односторонних случаев
Если нужно только «сервер шлёт клиенту», а в обратную сторону достаточно обычного REST — есть более простая технология: Server-Sent Events.
const events = new EventSource('/api/notifications/stream');
events.addEventListener('message', (e) => {
console.log('Новое уведомление:', e.data);
});
Под капотом — обычный HTTP-запрос с потоковым ответом. Сервер держит соединение открытым и пишет в него по мере событий. Браузер сам пересоединяется при разрыве, поддерживает форматы id: и event: для именованных сообщений.
SSE проще WebSocket и идеален для нотификаций, live-фидов, прогресс-баров долгих операций. Минус — только один направление (сервер → клиент).
Резюме
REST решает 80% задач. Оставшиеся 20% — нужны другие инструменты:
| Сценарий | Что выбрать |
| Чат, многопользовательская игра, совместное редактирование | WebSocket |
| Live-нотификации, прогресс долгой операции, лента событий | SSE (или WebSocket) |
| CRUD, формы, статичные ресурсы | REST |
| Сложный экран с множеством связанных сущностей | GraphQL |
| Микросервисы между бэкендами | gRPC |