Server Sent Events SSE
Server-Sent Events: Einfache Echtzeit-Updates
SSE ist die einfache Alternative zu WebSockets für unidirektionale Updates. Perfekt für Notifications, Live-Feeds und Dashboards.
SSE vs. WebSocket
| Feature | SSE | WebSocket |
|---|---|---|
| Richtung | Server → Client | Bidirektional |
| Protokoll | HTTP | WS/WSS |
| Reconnect | Automatisch | Manuell |
| Komplexität | Einfach | Komplexer |
| Browser-Support | Alle modernen | Alle modernen |
| Datenformat | Text | Text + Binär |
Client-Implementierung
// EventSource API
const eventSource = new EventSource('/events');
// Verbindung geöffnet
eventSource.onopen = () => {
console.log('Verbunden');
};
// Standard message Event
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Nachricht:', data);
};
// Benannte Events
eventSource.addEventListener('notification', (event) => {
const data = JSON.parse(event.data);
showNotification(data);
});
eventSource.addEventListener('update', (event) => {
const data = JSON.parse(event.data);
updateDashboard(data);
});
// Fehler (automatischer Reconnect!)
eventSource.onerror = (error) => {
console.log('Verbindung verloren, reconnecting...');
};
// Verbindung schließen
function disconnect() {
eventSource.close();
}
Node.js Server
const express = require('express');
const app = express();
app.get('/events', (req, res) => {
// SSE Headers
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// Initial message
res.write('data: {"type":"connected"}\n\n');
// Periodische Updates
const interval = setInterval(() => {
const data = {
time: new Date().toISOString(),
value: Math.random()
};
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
// Cleanup bei Disconnect
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(3000);
PHP Server
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// Buffering deaktivieren
ob_implicit_flush(true);
ob_end_flush();
$counter = 0;
while (true) {
// Verbindung prüfen
if (connection_aborted()) break;
// Event senden
$data = json_encode([
'time' => date('c'),
'counter' => $counter++
]);
echo "data: {$data}\n\n";
// Wichtig: Buffer flushen
flush();
sleep(1);
}
SSE Event-Format
# Einfache Nachricht
data: Hello World
# JSON-Daten
data: {"user":"Max","message":"Hallo"}
# Mehrzeilige Daten
data: Zeile 1
data: Zeile 2
data: Zeile 3
# Benanntes Event
event: notification
data: {"title":"Neue Nachricht"}
# Event ID (für Reconnect)
id: 12345
data: {"message":"Mit ID"}
# Retry-Interval (ms)
retry: 5000
data: Reconnect in 5 Sekunden
# Vollständiges Beispiel
id: 42
event: update
retry: 3000
data: {"status":"online","users":5}
Reconnect mit Last-Event-ID
// Server - Node.js
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
// Letzte ID vom Client
const lastId = req.headers['last-event-id'];
if (lastId) {
// Verpasste Events nachholen
const missedEvents = getMissedEvents(lastId);
missedEvents.forEach(event => {
res.write(`id: ${event.id}\n`);
res.write(`data: ${JSON.stringify(event.data)}\n\n`);
});
}
// Neue Events
let eventId = lastId ? parseInt(lastId) : 0;
const interval = setInterval(() => {
eventId++;
res.write(`id: ${eventId}\n`);
res.write(`data: ${JSON.stringify({ id: eventId })}\n\n`);
}, 1000);
req.on('close', () => clearInterval(interval));
});
Nginx Konfiguration
location /events {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Connection "";
# SSE-spezifisch: Buffering deaktivieren
proxy_buffering off;
proxy_cache off;
# Timeouts für lange Verbindungen
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# Chunked Transfer
chunked_transfer_encoding on;
}
Mit Authentifizierung
// Client - Token über URL (nicht ideal, aber einzige Option)
const eventSource = new EventSource('/events?token=' + authToken);
// Besser: Cookies nutzen
// Server setzt HttpOnly Cookie, wird automatisch mitgesendet
const eventSource = new EventSource('/events', {
withCredentials: true
});
// Server prüft Cookie/Session
app.get('/events', authenticateMiddleware, (req, res) => {
// User aus Session
const userId = req.user.id;
// ...
});
Broadcast an mehrere Clients
const clients = new Map();
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
const clientId = Date.now();
clients.set(clientId, res);
req.on('close', () => {
clients.delete(clientId);
});
});
// Broadcast-Funktion
function broadcast(event, data) {
const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
clients.forEach((res, clientId) => {
res.write(message);
});
}
// Nutzung
broadcast('notification', { message: 'Neue Nachricht!' });
💡 Tipp:
SSE ist ideal für Echtzeit-Dashboards. Nutzen Sie Enjyn Analytics für Live-Statistiken.