Server-Sent Events (SSE)

25 октября 2026 · ~8 мин чтения

протокол веб стриминг

Server-Sent Events (SSE)

Server-Sent Events (SSE, события от сервера) — это стандартный способ долго держать HTTP-соединение открытым и передавать через него текстовые события от сервера клиенту. Клиент получает их по мере появления, не ожидая завершения всей операции.

История

SSE вырос из практики веб-разработчиков, которым нужно было получать обновления с сервера без постоянных запросов из браузера. До появления удобного браузерного интерфейса разработчики применяли long polling (длинный опрос): браузер отправлял запрос, сервер отвечал, а затем браузер сразу повторял запрос. Это работало, но создавало лишние циклы запросов и усложняло поддержку соединения.

Браузерное API EventSource появилось в ходе стандартизации HTML5. Описание SSE входит в HTML Living Standard, который поддерживает WHATWG. Это не отдельный протокол транспортного уровня: события идут поверх обычного HTTP, обычно через HTTP/1.1 или HTTP/2. Формат и поведение определяются браузерным API и стандартом, а не специальным портом или отдельной сетью.

SSE стал распространённым решением для уведомлений, лент событий и вывода ответа по мере генерации. В современных браузерах API EventSource поддерживается широко, но устроен прежде всего для GET-запросов и не позволяет произвольно задать заголовки запроса. Для POST-запросов и особой авторизации часто используют fetch() и самостоятельно читают поток ответа.

Важные вехи — появление EventSource в браузерах, формализация формата событий в HTML и распространение HTTP/2, позволяющего эффективнее обслуживать множество одновременных запросов в рамках одного соединения. Точные даты внедрения отдельных браузерных реализаций различаются; SSE не следует приписывать одной компании или одной версии браузера.

Что это такое

SSE — однонаправленный поток: сервер отправляет события, клиент их принимает. Клиент не отправляет ответные сообщения по этому же каналу, как при двунаправленном WebSocket. Для действий пользователя браузер делает обычный HTTP-запрос, а SSE-соединение используется отдельно для получения обновлений.

Тело ответа — текст UTF-8, организованный в блоки. В блоке могут быть поля event, data, id и retry. Например, event: progress задаёт тип события, data: 42 содержит данные, а пустая строка завершает блок. Несколько строк data: объединяются. Комментарий, начинающийся с двоеточия, часто служит heartbeat (сигналом жизни), чтобы промежуточные узлы не считали соединение простаивающим.

Ответ обычно имеет тип text/event-stream. Сервер не должен сначала собирать весь вывод и только затем отправлять одним ответом: смысл SSE — последовательная доставка фрагментов. Браузерный EventSource автоматически переподключается после разрыва. Если сервер задаёт идентификатор события через id:, клиент при повторном подключении может сообщить его в Last-Event-ID; приложение тогда может попытаться продолжить поток с нужного места.

SSE часто выбирают для вывода генеративной модели, прогресса импорта, уведомлений и обновления состояния фоновой задачи. Однако стандарт не гарантирует доставку каждого события ровно один раз, не хранит историю и не задаёт бизнес-семантику. При переподключении серверу и приложению нужно договориться, как находить пропуски и повторы.

SSE vs WebSocket: SSE проще, работает как обычный HTTP-ответ и подходит, когда данные в основном идут сервер → клиент. WebSocket даёт постоянный двунаправленный канал, но требует иной модели соединения и более сложного управления. SSE vs polling: polling периодически спрашивает «что нового?», тогда как SSE позволяет серверу отправить событие сразу после появления.

Аналогии из жизни

  1. Табло отправлений. Вместо того чтобы пассажир снова и снова спрашивал о статусе поезда, табло обновляется при поступлении сведений. Это помогает понять инициативу сервера. Где ломается: табло обычно показывает общую картину многим людям, а HTTP-поток принадлежит клиенту и может оборваться при смене сети.
  2. Радиоэфир. Ведущий последовательно сообщает новости, а слушатель принимает их по мере выхода. Это похоже на поток, который нельзя перемотать, если вещатель не хранит архив. Где ломается: SSE допускает идентификаторы и переподключения, а радио обычно не воспроизводит пропущенное автоматически.
  3. Заказ в кафе. Экран показывает «принят», «готовится», «готов», и новая отметка появляется по мере изменения заказа. Где ломается: статусы — бизнес-состояние, которое можно запросить заново; SSE — только канал доставки и не определяет, какой статус правильный.

Как это работает

  1. Клиент открывает HTTP-запрос. С EventSource это обычно GET /events; если нужны тело запроса или специальные заголовки, используют fetch() и потоковый reader.
  2. Сервер отвечает успешным статусом и заголовком Content-Type: text/event-stream; charset=utf-8. Ответ остаётся открытым. Также важны корректные CORS и авторизация, если клиент и сервер находятся на разных origin.
  3. Сервер передаёт события в текстовом формате. Например:
event: progress
data: {"percent": 40}
id: task-7-12

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

: keep-alive

  1. Браузер разбирает блоки. Обработчик message получает события без явно заданного типа, а именованные типы слушаются через addEventListener, например progress. Поле data приходит текстом; JSON нужно разобрать отдельно.
  2. При сетевом обрыве EventSource пытается подключиться снова. retry: 3000 может задать задержку переподключения в миллисекундах. Идентификатор в id: позволяет браузеру сообщить серверу последний полученный ID, но серверу всё равно нужно хранить события или уметь восстановить состояние.

На сервере принципиально важно сбрасывать буферы после записи доступного фрагмента. Иначе приложение уже сформировало событие, но клиент увидит его лишь в конце ответа. Прокси, CDN, веб-сервер или компрессия тоже могут накапливать данные. Для стриминга весь тракт — от источника события до кода браузера — должен пропускать фрагменты без нежелательной буферизации и не закрывать соединение преждевременно.

Ресурсы конечны: каждый активный поток использует соединение, память и иногда задачу на сервере. Нужны тайм-ауты с учётом долгих соединений, отмена работы при отключении клиента, ограничение подключений и периодические heartbeat-сообщения. В HTTP/1.1 браузер может ограничивать число соединений к одному origin; HTTP/2 уменьшает эту проблему мультиплексированием, но не отменяет серверных лимитов.

Где встречается в обычной жизни

Где встречается в IT и бизнесе

Кто пользуется

SSE — веб-стандарт, а не продукт одного поставщика. Его используют браузерные приложения и серверы, которым нужно доставлять события клиенту через HTTP. Реализации и библиотеки доступны для популярных серверных платформ, а EventSource встроен в браузеры.

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

Альтернативы и конкуренты

Когда НЕ стоит использовать

Связанные понятия

Литература и источники

Где встретилось у меня

SSE всплыл при обсуждении доставки постепенно генерируемых ответов в интерфейсе и устранения буферизации на пути между сервером, прокси и клиентом. В том же контексте обсуждались авторизация сотрудников и проверка качества приложения; внутренние подробности здесь не приводятся.

Краткое резюме