Server-Sent Events in TypeScript: Daten-Streaming ohne Kopfschmerzen
\n\nStellen Sie sich vor: Ihr Server generiert Daten – Logs, Benachrichtigungen, Wechselkursaktualisierungen – und muss diese sofort an das Frontend senden. WebSocket? Leistungsstark, aber überdimensioniert. Polling? Langsam und verbraucht Traffic. Es gibt einen dritten Weg – elegant, einfach und unglaublich nützlich: Server-Sent Events (SSE).
\n\nIn diesem Artikel analysieren wir SSE in TypeScript von A bis Z. Wir schreiben Client und Server, lernen Fehlerbehandlung und Wiederverbindung, und vor allem verstehen wir, wann SSE anderen Ansätzen wirklich überlegen ist. Los geht's!
\n\nWas sind Server-Sent Events und wozu braucht man sie?
\n\nServer-Sent Events sind ein HTML5-Standard, der es dem Server ermöglicht, Daten in Echtzeit über eine einzige HTTP-Verbindung an den Client zu senden. Im Gegensatz zu WebSocket ist SSE unidirektional: Nur der Server sendet Nachrichten. Aber genau darin liegt seine Stärke – er ist maximal einfach und erfordert keine zusätzlichen Bibliotheken.
\n\nWann sollte man SSE wählen?
\n\n- \n
- Unidirektionales Streaming: Benachrichtigungen, Logs, Wechselkurse, Aktienticker. \n
- Einfache Integration: Funktioniert über den standardmäßigen
EventSourceim Browser – keine npm-Pakete nötig. \n - Automatische Wiederverbindung: Der Browser stellt die Verbindung bei Unterbrechung selbstständig wieder her. \n
- Kompatibilität mit HTTP/2: Multiplexing stört nicht, im Gegensatz zu WebSocket. \n
Beachten Sie jedoch: SSE kann keine Daten vom Client an den Server senden (dafür verwenden Sie normale POST-Anfragen) und wird in älteren Browsern nicht unterstützt (IE – hallo).
\n\nServerseite: SSE in TypeScript + Express schreiben
\n\nBeginnen wir mit dem Backend. Wir erstellen einen einfachen Server mit Node.js, Express und TypeScript. Installieren Sie die Abhängigkeiten:
\n\nnpm init -y\nnpm install express cors\nnpm install -D typescript @types/express @types/node ts-node\nnpx tsc --init\n\nJetzt schreiben wir den Server selbst. Der Schlüsselpunkt ist das Setzen der richtigen Header und das Nachrichtenformat.
\n\n// server.ts\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\n\n// Endpunkt für SSE\napp.get('/events', (req: Request, res: Response) => {\n // Header für SSE setzen\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n\n // Erste Nachricht senden\n res.write('data: {"message": "Verbindung hergestellt"}\\n\\n');\n\n // Alle 3 Sekunden ein Ereignis senden\n const intervalId = setInterval(() => {\n const data = JSON.stringify({\n time: new Date().toISOString(),\n value: Math.random() * 100,\n });\n res.write(`data: ${data}\\n\\n`);\n }, 3000);\n\n // Client-Trennung behandeln\n req.on('close', () => {\n clearInterval(intervalId);\n res.end();\n console.log('Client hat die Verbindung getrennt');\n });\n});\n\nconst PORT = 3000;\napp.listen(PORT, () => console.log(`SSE-Server gestartet auf Port ${PORT}`));\n\nBeachten Sie das Format: Jede Nachricht beginnt mit data: und endet mit zwei Zeilenumbrüchen \\n\\n. Man kann auch id, event und retry angeben – aber das ist die Basis.
Benannte Ereignisse senden
\n\nManchmal muss man Nachrichtentypen unterscheiden. Fügen wir das Feld event hinzu:
res.write('event: update\\n');\nres.write(`data: ${JSON.stringify({ id: 1, title: 'Neuer Beitrag' })}\\n\\n`);\n\n// Und dann ein anderes Ereignis\nres.write('event: notification\\n');\nres.write('data: {"level": "info", "text": "Server läuft"}\\n\\n');\n\nAuf der Client-Seite können wir dann bestimmte Ereignisse abonnieren.
\n\nClientseite: Ereignisse in TypeScript empfangen
\n\nJetzt schreiben wir den Client. Im Browser wird der eingebaute EventSource verwendet. Aber wenn