SSE (Server-Sent Events) — standard W3C, pozwalający serwerowi wysyłać strumieniowe dane do klienta przez pojedyncze połączenie HTTP w trybie jednostronnym. W przeciwieństwie do WebSocket, SSE działa na zwykłym HTTP i nie wymaga specjalnego protokołu ani biblioteki po stronie klienta. Według danych specyfikacji W3C HTML Living Standard (2025), EventSource API jest obsługiwane we wszystkich nowoczesnych przeglądarkach, w tym Chrome, Firefox, Safari i Edge.
Najważniejsze
SSE (Server-Sent Events) — technologia pozwalająca serwerowi WWW na wysyłanie danych do klienta w dowolnym momencie po nawiązaniu połączenia. Jest standaryzowana przez WHATWG jako część HTML Living Standard i wykorzystuje typ MIME text/event-stream. SSE obsługuje przesyłanie danych tekstowych z możliwością określenia identyfikatora wiadomości, typu zdarzenia i opóźnienia ponownego połączenia.
W przeciwieństwie do WebSocket, który wymaga protokołu dwukierunkowego i żądania upgrade, SSE działa na zwykłym HTTP. Serwer ustawia nagłówek Content-Type: text/event-stream, wysyła dane porcjami i utrzymuje połączenie otwarte. Klient odbiera dane przez przeglądarkowe EventSource API, które automatycznie parsuje strumień i generuje zdarzenia.
Według danych CanIUse (2025), EventSource API jest obsługiwane w 97,5% przeglądarek globalnie. Nie jest obsługiwane w Internet Explorer i niektórych przeglądarkach mobilnych (Samsung Internet do wersji 7.0). Dla tych przypadków istnieją polifille emulujące EventSource przez XHR streaming. SSE nie działa z HTTP/1.1 pipelining, ale jest w pełni kompatybilny z HTTP/2 server push.
SSE został zaproponowany jako część specyfikacji HTML5 w 2009 roku pod nazwą Server-Sent DOM Events. Pierwsza implementacja pojawiła się w Opera 9.0, następnie w Firefox 6.0 (2011), Chrome 9.0 (2011) i Safari 5.0 (2010). W 2015 roku specyfikacja została wydzielona jako osobna sekcja HTML Living Standard. Mimo dziesięcioletniej historii SSE pozostaje mniej popularny niż WebSocket ze względu na swoją jednostronną naturę.
Mechanizm działania SSE jest następujący: klient tworzy instancję EventSource z URL endpointu serwera. Przeglądarka wysyła żądanie GET z nagłówkiem Accept: text/event-stream. Serwer odpowiada statusem 200 OK i nagłówkiem Content-Type: text/event-stream, po czym zaczyna wysyłać dane w formacie event-stream. Połączenie pozostaje otwarte, dopóki serwer nie wyśle sygnału zakończenia lub klient nie wywoła close().
Po stronie serwera dane są wysyłane porcjami (chunked transfer encoding). Każdy blok danych to wiadomość tekstowa składająca się z wierszy pól (event, data, id, retry). Serwer może wysyłać wiadomości w dowolnym momencie, co czyni SSE idealnym rozwiązaniem dla powiadomień i aktualizacji statusu. Połączenie nie wymaga stałej wymiany pakietów heartbeat (jak WebSocket), chociaż pole retry kontroluje częstotliwość ponownego łączenia.
Według danych testów wydajnościowych (2024), SSE zapewnia przepustowość do 10 000 wiadomości na sekundę na jedno połączenie przy rozmiarze wiadomości 256 bajtów. Po stronie serwera każde połączenie SSE zużywa około 5–10 KB pamięci, co pozwala jednemu serwerowi obsługiwać 50 000+ jednoczesnych połączeń przy 1 GB RAM. To znacznie mniej niż w przypadku WebSocket ze względu na brak protokołu binarnego.
Format text/event-stream — prosty protokół tekstowy, w którym każda wiadomość składa się z nazwanych pól rozdzielonych znakami nowej linii. Każde pole ma format «NazwaPola: wartość». Wiadomości są rozdzielane dwoma znakami nowej linii ( ).
Obsługiwane pola: event (typ zdarzenia, domyślnie message), data (ciąg danych, może być wieloliniowy), id (ostatni identyfikator zdarzenia, zapisywany w Last-Event-ID), retry (opóźnienie ponownego połączenia w milisekundach). Komentarze zaczynają się od dwukropka (:) i są ignorowane przez parser, ale mogą być używane do heartbeat.
| Pole | Wymagane | Przeznaczenie |
|---|---|---|
| event | Nie | Typ zdarzenia (message domyślnie) |
| data | Tak | Ciąg danych wiadomości |
| id | Nie | Identyfikator zdarzenia dla Last-Event-ID |
| retry | Nie | Opóźnienie ponownego połączenia w ms |
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001
event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000
event: close
data: Session ended
EventSource API — wbudowany interfejs przeglądarki do odbioru SSE. Aby utworzyć połączenie, wystarczy wywołać konstruktor z URL endpointu. EventSource automatycznie nawiązuje połączenie, obsługuje ponowne łączenie i parsuje przychodzące wiadomości na zdarzenia JavaScript.
Zdarzenia EventSource: open (połączenie nawiązane), message (otrzymano wiadomość bez określonego event), error (błąd połączenia). Dla zdarzeń niestandardowych (event: custom) można użyć addEventListener z nazwą zdarzenia. EventSource automatycznie wysyła nagłówek Last-Event-ID przy ponownym łączeniu, co pozwala serwerowi wznowić strumień od przerwanego miejsca.
Według danych dokumentacji MDN (2025), EventSource obsługuje CORS i przesyłanie credentials (withCredentials). Do przesyłania niestandardowych nagłówków lub treści żądania EventSource się nie nadaje — wymagana jest ręczna implementacja przez fetch + ReadableStream. EventSource nie obsługuje danych binarnych — tylko tekst i JSON.
const eventSource = new EventSource('/api/events/stream');
eventSource.addEventListener('open', () => {
console.log('Połączenie SSE otwarte');
});
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Otrzymano:', data);
renderUpdate(data);
});
eventSource.addEventListener('notification', (event) => {
const notification = JSON.parse(event.data);
showNotification(notification.text);
});
eventSource.addEventListener('error', (error) => {
console.error('Błąd SSE:', error);
// Automatyczne ponowne łączenie przeglądarki
});
// Zamknij połączenie
eventSource.close();
SSE i WebSocket — różne technologie komunikacji w czasie rzeczywistym, każda ze swoimi mocnymi stronami. WebSocket nadaje się do dwukierunkowej wymiany danych (czaty, gry, wspólne edytowanie), SSE — do jednostronnych strumieni z serwera do klienta (powiadomienia, kanały informacyjne, tickery).
Kluczowa różnica — WebSocket wymaga żądania upgrade z HTTP/1.1 do protokołu WebSocket (ws://), co może być blokowane przez proxy korporacyjne. SSE działa na zwykłym HTTP, przechodzi przez wszystkie proxy i nie wymaga specjalnej konfiguracji serwera. SSE jest również prostszy w implementacji — serwer nie potrzebuje dodatkowej biblioteki, wystarczy odpowiednio sformować odpowiedź HTTP.
Według danych testów porównawczych (2024), na jednym procesie serwerowym SSE obsługuje o 30–50% więcej połączeń niż WebSocket ze względu na prostszy protokół. Jednak latency SSE jest wyższe (50–200 ms wobec 10–50 ms dla WebSocket) z powodu wykorzystania chunked HTTP, a nie w pełni dwukierunkowego strumienia z ramkami binarnymi.
| Charakterystyka | SSE | WebSocket |
|---|---|---|
| Kierunek | Serwer → klient | Dwukierunkowy |
| Protokół | HTTP (text/event-stream) | ws:// / wss:// (RFC 6455) |
| Przeglądarki | 97,5% (wbudowany EventSource) | 97% (wbudowany WebSocket) |
| Dane | Tylko tekst / JSON | Tekst + binarne (Blob, ArrayBuffer) |
| Obsługa proxy | Przechodzi przez wszystkie proxy | Wymaga konfiguracji proxy |
| Ponowne łączenie | Automatyczne (przeglądarka) | Ręczna implementacja |
| Historia | Last-Event-ID | Brak wbudowanej historii |
Implementacja SSE na serwerze nie wymaga bibliotek — wystarczy ustawić odpowiednie nagłówki HTTP i wysyłać dane w formacie text/event-stream. Rozważmy przykład na Node.js z użyciem wbudowanego modułu http. Serwer ustawia nagłówki Content-Type i Cache-Control, a następnie wysyła wiadomości co N sekund.
Według danych MDN Web Docs (2025), obowiązkowe nagłówki dla SSE: Content-Type: text/event-stream, Cache-Control: no-cache i Connection: keep-alive. Bez Cache-Control przeglądarka może zbuforować strumień SSE, co doprowadzi do zatrzymania dostarczania. Connection: keep-alive wyraźnie wskazuje przeglądarce, aby utrzymywać połączenie otwarte.
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
let eventId = 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`event: update\n`);
res.write(`data: {"czas": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
}).listen(3000);
from flask import Response, Flask
import time
import json
app = Flask(__name__)
@app.route('/stream')
def stream():
def generate():
event_id = 0
while True:
event_id += 1
data = json.dumps(
{'ticker': 'AAPL', 'price': 150.25})
yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
time.sleep(1)
return Response(generate(),
mimetype='text/event-stream')
Użycie SSE w aplikacjach mobilnych jest ograniczone brakiem natywnej implementacji EventSource dla iOS i Android. Na platformach mobilnych SSE jest implementowane przez biblioteki zewnętrzne: na iOS — przez URLSession z NSURLProtocol, na Android — przez OkHttp z obsługą SSE (okhttp-sse). Dla React Native i Flutter dostępne są pakiety emulujące EventSource.
Na iOS natywna implementacja SSE jest możliwa przez URLSessionDataDelegate. Podczas otrzymywania danych w metodzie urlSession(_:dataTask:didReceive:) aplikacja gromadzi bufor i ręcznie parsuje format event-stream. Według danych bloga iOS-development (2024), zużycie baterii przy SSE na iOS jest o 40% niższe niż przy stałym połączeniu WebSocket ze względu na brak pakietów heartbeat.
Na Android OkHttp udostępnia klasę EventSource.Factory do subskrypcji strumieni SSE. Aplikacje Android mogą używać SSE do powiadomień, gdy FCM jest niedostępny, lub do synchronizacji danych w tle. SSE na Android dobrze współpracuje z WorkManager dla długotrwałych zadań w tle. Według danych dokumentacji OkHttp (2025), okhttp-sse obsługuje automatyczne ponowne łączenie z niestandardowym listenerem.
Często zadawane pytania
SSE — transmisja jednostronna (serwer → klient) przez HTTP, nie wymaga bibliotek po stronie klienta. WebSocket — transmisja dwukierunkowa z protokołem binarnym. SSE jest prostszy w implementacji, WebSocket nadaje się do zadań, gdzie klient również wysyła dane.
Nie, SSE przesyła tylko dane tekstowe. Dla danych binarnych (obrazy, audio) wymagane jest kodowanie Base64, które zwiększa rozmiar o 33%. Dla strumieni binarnych lepiej użyć WebSocket.
EventSource automatycznie łączy się ponownie po przerwaniu. Czas opóźnienia jest ustawiany przez pole retry w strumieniu (domyślnie 1000 ms). Przy ponownym łączeniu przeglądarka wysyła nagłówek Last-Event-ID, pozwalający serwerowi przywrócić strumień od przerwanego miejsca.
Każda przeglądarka ma ograniczenie liczby jednoczesnych połączeń HTTP z jedną domeną. Dla HTTP/1.1 — 6–8 połączeń na domenę, dla HTTP/2 — do 100. SSE wykorzystuje jedno połączenie, więc nie konkuruje z innymi żądaniami.
SSE nadaje się tylko do odbierania wiadomości (przychodzące). Do wysyłania wiadomości (wychodzące) wymagane jest osobne żądanie HTTP (POST). Do pełnego czatu wygodniej użyć WebSocket lub Socket.IO z komunikacją dwukierunkową w jednym połączeniu.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również