HTTP устроен как «вопрос — ответ»: клиент спрашивает, сервер отвечает. Но у многих задач направление обратное: пришло сообщение в чат, изменился статус заказа, обновился курс — сервер должен сообщить клиенту. Обычный HTTP так не умеет, и за годы выработалось три рабочих способа: long polling, Server-Sent Events и WebSocket.
Long polling: растянутый вопрос
Простейшая идея: клиент спрашивает «есть новости?», а сервер не отвечает, пока новости не появятся (или не истечёт таймаут, скажем 30 секунд). Получив ответ, клиент немедленно спрашивает снова.
Плюсы: работает поверх обычного HTTP везде, где работает HTTP — любые прокси, балансировщики, файрволы. Минусы: постоянно висящие запросы занимают ресурсы, между ответом и новым запросом есть щель (событие подождёт), каждый цикл несёт полные HTTP-заголовки. Сегодня это запасной вариант — для сред, где ничего лучше не проходит.
Server-Sent Events: односторонний поток
SSE — часть веб-стандартов: клиент открывает обычное HTTP-соединение, сервер держит его и пишет события текстовым потоком text/event-stream:
data: {"orderId": 42, "status": "SHIPPED"}
data: {"orderId": 43, "status": "PAID"}
Ключевые свойства:
- однонаправленность — события идут только от сервера; запросы клиент шлёт обычным HTTP рядом;
- автопереподключение встроено: браузерный EventSource сам восстанавливает соединение и передаёт
Last-Event-ID, чтобы дочитать пропущенное; - это по-прежнему HTTP: сжатие, авторизация заголовками, прокси — всё стандартно.
SSE — недооценённый вариант: для «сервер уведомляет клиента» (статусы, ленты, прогресс операций, курсы) он закрывает задачу заметно дешевле WebSocket.
WebSocket: полный дуплекс
WebSocket начинается как HTTP-запрос с заголовком Upgrade: websocket, после рукопожатия соединение превращается в постоянный двунаправленный канал: обе стороны шлют сообщения когда угодно, без HTTP-заголовков на каждое.
Это единственный из трёх способов с настоящей связью в обе стороны и минимальными накладными расходами на сообщение — цена соответствующая:
- протокол другой: нужна поддержка на всём пути (прокси, балансировщики, таймауты простоя);
- переподключение, восстановление подписок и доставка пропущенного — ваша забота (потому поверх WebSocket обычно живёт протокол уровнем выше: STOMP, socket.io и подобные);
- тысячи постоянных соединений — отдельная статья нагрузки на сервер.
Сравнение и выбор
| Long polling | SSE | WebSocket | |
|---|---|---|---|
| Направление | сервер → клиент | сервер → клиент | оба |
| Транспорт | обычный HTTP | обычный HTTP | свой протокол после Upgrade |
| Переподключение | само по природе | встроено (EventSource) | руками / библиотекой |
| Накладные расходы | высокие | низкие | минимальные |
| Когда брать | враждебная среда | уведомления, ленты, прогресс | чат, игры, совместное редактирование |
Правило выбора: нужен пуш от сервера — начните с SSE; нужен диалог (клиент часто пишет: чат, курсор в совместном документе, игры) — WebSocket; ничего не проходит — long polling.
Масштабирование: общая грабля
С постоянными соединениями ломается привычная модель «любой запрос — на любой экземпляр»: соединение живёт на конкретном сервере, а событие для клиента может родиться на другом. Стандартное решение — общая шина: экземпляры публикуют события в брокер или Redis Pub/Sub, и каждый доставляет их своим подключённым клиентам. Плюс придётся подружить балансировщик с длинными соединениями: таймауты простоя, при необходимости — привязка клиента к экземпляру.
И помните про устойчивость: любое постоянное соединение рвётся — вопрос не «если», а «когда»; переподключение и дочитывание пропущенного проектируются с первого дня.
Коротко
- Long polling — запрос, который ждёт события; работает везде, но дорог и с щелями между циклами — запасной вариант.
- SSE — односторонний поток событий поверх обычного HTTP со встроенным переподключением; лучший старт для «сервер уведомляет клиента».
- WebSocket — двунаправленный канал с минимальными накладными расходами; берут для диалоговых сценариев, платят своей обвязкой переподключений и доставки.
- Масштабирование постоянных соединений — через общую шину событий между экземплярами; разрывы и дочитывание — часть дизайна, не аварийный случай.
Что почитать дальше
- HTTP: как устроен протокол — фундамент, поверх которого всё это работает.
- Балансировка нагрузки — длинные соединения и балансировщик.
- Надёжность сети — таймауты, повторы и жизнь с разрывами.