Розробка 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
    1418
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    983
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1243
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    983
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    997

При обновлении статуса заказа клиенту приходится перезагружать страницу или тянуть 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-оновлення — отримайте консультацію.