Разработка Server-Sent Events (SSE) для веб-приложения

При обновлении статуса заказа клиенту приходится перезагружать страницу или тянуть API каждые 5 секунд. Это увеличивает нагрузку на сервер и ухудшает UX. Аналогичная ситуация — на финансовой платформе, где котировки меняются каждую секунду, но WebSocket избыточен, а постоянные поллинги убивают базу

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка Server-Sent Events (SSE) для веб-приложения
Средний
от 1 дня до 3 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1414
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    982
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    994

При обновлении статуса заказа клиенту приходится перезагружать страницу или тянуть API каждые 5 секунд. Это увеличивает нагрузку на сервер и ухудшает UX. Аналогичная ситуация — на финансовой платформе, где котировки меняются каждую секунду, но WebSocket избыточен, а постоянные поллинги убивают базу данных. Мы решаем эту проблему с помощью Server-Sent Events (SSE) — технологии однонаправленной потоковой передачи данных от сервера к клиенту через HTTP. Наш опыт показывает: SSE снижает количество запросов в 10 раз и обеспечивает доставку событий за <1 с.

Почему SSE, а не WebSocket?

Критерий SSE WebSocket
Направление Одностороннее (сервер→клиент) Двустороннее
HTTP-совместимость Нативный HTTP/1.1 Требует upgrade
Автопереподключение Встроенное Нужно реализовывать
Работа через прокси Без проблем Часто блокируется
CORS GET без preflight Preflight для не-GET

SSE лучше подходит для задач, где важны уведомления и live-обновления. Отправка данных от клиента редка. Настройка SSE в среднем занимает в два раза меньше времени, чем WebSocket. Например, для уведомлений о статусе заказа SSE идеален, а для чата — WebSocket.

Как SSE масштабируется на несколько серверов?

В одном проекте для крупного e-commerce мы реализовали SSE с распределённой доставкой через Redis Pub/Sub. Клиент получил уменьшение времени обновления статуса заказа с 5 минут до 1 секунды. При этом система выдерживает 10 000 одновременных подключений без потери событий. Масштабирование достигается за счёт брокера сообщений: все серверы подписываются на общий канал и публикуют события для всех клиентов. Мы используем этот паттерн более чем в 30 проектах за последние годы.

Техническая реализация

Формат SSE

Ответ сервера — text/event-stream с полями data:, event:, id:, retry::

HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive data: {"type":"notification","message":"Новый заказ"} event: order_update data: {"orderId":"123","status":"shipped"} id: msg_456 retry: 3000 : comment (игнорируется клиентом) 

Серверный endpoint (Node.js + Express)

Полный код серверного endpoint с heartbeat и реестром клиентов
app.get('/api/events', (req, res) => { const userId = req.user.id; res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'X-Accel-Buffering': 'no', // для Nginx: отключить буферизацию }); // Немедленно отправляем первый пакет (обход nginx буферизации) res.write(':ok\n\n'); // Добавляем клиента в реестр const clientId = nanoid(); clients.set(clientId, { res, userId }); // Heartbeat каждые 15 секунд const heartbeat = setInterval(() => { res.write(': ping\n\n'); }, 15000); req.on('close', () => { clearInterval(heartbeat); clients.delete(clientId); }); }); // Отправка события конкретному пользователю function sendToUser(userId: string, event: string, data: object) { clients.forEach(({ res, userId: uid }) => { if (uid === userId) { res.write(`event: ${event}\n`); res.write(`data: ${JSON.stringify(data)}\n\n`); } }); } // Broadcast всем function broadcast(event: string, data: object) { clients.forEach(({ res }) => { res.write(`event: ${event}\n`); res.write(`data: ${JSON.stringify(data)}\n\n`); }); } 

Клиент на EventSource

Подключение через EventSource с поддержкой именованных событий:

const eventSource = new EventSource('/api/events', { withCredentials: true }); // Дефолтные события (event: без имени) eventSource.onmessage = (e) => { const data = JSON.parse(e.data); console.log('Message:', data); }; // Именованные события eventSource.addEventListener('order_update', (e) => { const order = JSON.parse(e.data); updateOrderStatus(order.orderId, order.status); }); eventSource.addEventListener('notification', (e) => { showNotification(JSON.parse(e.data).message); }); // Обработка ошибок eventSource.onerror = (e) => { if (eventSource.readyState === EventSource.CLOSED) { console.log('Соединение закрыто, автоматически переподключается...'); } }; 

Подробнее об EventSource можно прочитать в официальной документации: MDN Web Docs.

Масштабирование с Redis Pub/Sub

sub.subscribe('user:events', (message) => { const { userId, event, data } = JSON.parse(message); sendToUser(userId, event, data); }); // Из любого сервиса await pub.publish('user:events', JSON.stringify({ userId: 'user_123', event: 'payment_completed', data: { amount: 5000 } })); 

Примеры именованных событий

Событие Формат данных
notification {"type":"success","message":"..."}
order_update {"orderId":"123","status":"shipped"}
payment_completed {"amount":5000,"currency":"USD"}

Реальный кейс: SSE для финансовой платформы

Для стартапа, предоставляющего данные о криптовалютах в реальном времени, мы спроектировали систему на SSE. Требовалось отправлять котировки 50+ валютных пар тысячам пользователей без задержек и без нагрузки на клиентские базы. Решение: каждый пользователь подписывается на нужные пары через кастомный endpoint, а серверы объединяют события по протоколу Redis Pub/Sub. В итоге — задержка доставки не более 200 мс даже при 10 000 подключений. Это позволило отказаться от WebSocket, упростить инфраструктуру и сэкономить на разработке. Гарантируем стабильность такой схемы под высокой нагрузкой.

Как обеспечить надежное переподключение?

SSE автоматически переподключается, но важно настроить heartbeat. Если сервер не отправляет данные 30 секунд, браузер может закрыть соединение. Поэтому мы отправляем пустой комментарий (: ping) каждые 15 секунд. Это поддерживает соединение живым. Кроме того, используйте заголовок X-Accel-Buffering: no для Nginx, чтобы данные не буферизировались.

Ограничения SSE

  • Только сервер → клиент — клиент не может отправить данные через SSE (только новые EventSource-запросы или отдельный API-запрос).
  • Лимит соединений в HTTP/1.1 — браузер ограничивает 6 соединений на домен. SSE занимает одно. Решение: HTTP/2 (один мультиплексируемый поток).
  • IE не поддерживает — полифилл eventsource для старых браузеров.

Что входит в работу и типичные ошибки

  • Проектирование схемы событий и типов данных.
  • Реализация серверного endpoint с аутентификацией и heartbeat.
  • Клиентская интеграция (React hook, Angular service или нативный EventSource).
  • Нагрузочное тестирование до 10 000 подключений.
  • Документирование протокола и кода.
  • Обучение команды заказчика.

Типичные ошибки при внедрении SSE:

  • Не учитывают буферизацию Nginx — забывают заголовок X-Accel-Buffering: no.
  • Используют SSE для двусторонней связи — правильнее WebSocket.
  • Не ставят heartbeat — соединение может разорваться и не восстановиться.

Сроки

SSE-эндпоинт с аутентификацией, heartbeat, Redis-scaling: 3–5 дней. С типизированными событиями, client-side хуком (useSSE), интеграцией уведомлений: 1–2 недели.

Оценим ваш проект — свяжитесь с нами для консультации. За последние годы мы реализовали множество решений на SSE, гарантируем стабильность под высокой нагрузкой. Если вам нужно внедрить live-обновления — получите консультацию сегодня.