Die Frage vor der Technikwahl
Drei Angaben entscheiden fast immer, und keine davon ist technisch. Wie alt darf die Information im schlimmsten Fall sein? Wer schickt, nur der Server oder beide Seiten? Und wie viele Verbindungen sind gleichzeitig offen?
Ein Dashboard, das Tagesumsätze zeigt, ist mit einer Aktualisierung pro Minute völlig in Ordnung. Ein Chat ist es nicht. Zwischen diesen beiden Fällen liegen zwei Größenordnungen an Aufwand, und der Unterschied entsteht genau an dieser Stelle, nicht später im Code.
Der teure Fehler passiert, wenn jemand die Antwort auf Frage eins nie stellt und direkt bei WebSockets landet. Dann betreibst du eine dauerhafte Verbindung samt Wiederverbindungslogik, Sticky Sessions und Adapter für mehrere Instanzen, um eine Zahl anzuzeigen, die sich dreimal am Tag ändert.
Polling, und warum es öfter reicht als gedacht
Polling hat einen schlechten Ruf, den es meist nicht verdient. Es ist zustandslos, es überlebt jeden Load Balancer, es funktioniert durch jede Firmen-Firewall, und wenn dein Server neu startet, merkt es niemand. Für alles im Minutenbereich ist es die richtige Wahl.
Zwei Dinge machen den Unterschied zwischen naivem und ordentlichem Polling. Erstens gehört die Abfrage angehalten, wenn der Tab im Hintergrund liegt, sonst zahlst du für Anfragen, die niemand sieht. Zweitens brauchst du einen Rückzieher bei Fehlern, damit ein kurzer Ausfall nicht in eine Anfragenlawine mündet.
export function startPolling(load: () => Promise<void>, baseMs = 30000) {
let timer: ReturnType<typeof setTimeout>;
let failures = 0;
async function tick() {
// im hintergrund gar nicht erst laden
if (document.visibilityState === "visible") {
try {
await load();
failures = 0;
} catch {
failures += 1;
}
}
// backoff bis maximal 5 minuten, damit ein ausfall nicht eskaliert
const delay = Math.min(baseMs * 2 ** failures, 300000);
timer = setTimeout(tick, delay);
}
tick();
return () => clearTimeout(timer);
}Server-Sent Events: der unterschätzte Mittelweg
SSE ist eine offene HTTP-Verbindung, über die der Server schickt, wann er will. Der Client kann nichts zurücksenden, und genau deshalb ist es so einfach. Kein eigenes Protokoll, kein Upgrade-Handshake, und die Wiederverbindung ist im Browser schon eingebaut.
Für Benachrichtigungen, Fortschrittsanzeigen, Live-Logs oder Token-Streams aus einem Sprachmodell ist das die passende Wahl. Du brauchst keine zusätzliche Bibliothek, weder im Browser noch auf dem Server.
// server (nest / express)
@Get("events")
stream(@Res() res: Response) {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
// wichtig hinter nginx, sonst puffert der proxy die antwort
res.setHeader("X-Accel-Buffering", "no");
const send = (data: unknown) => res.write("data: " + JSON.stringify(data) + "\n\n");
const off = this.events.subscribe(send);
res.on("close", off);
}
// client: reconnect kommt vom browser, nichts weiter zu tun
const source = new EventSource("/api/events");
source.onmessage = (event) => setState(JSON.parse(event.data));WebSocket: wenn beide Seiten sprechen
Eine dauerhafte Verbindung in beide Richtungen, mit sehr geringer Latenz. Das brauchst du, wenn der Client häufig sendet und nicht nur empfängt: Chat, gemeinsames Bearbeiten, Spiele, Umfragen während eines Streams.
Der Preis dafür ist Betrieb. Du brauchst Sticky Sessions vor mehreren Instanzen, einen Adapter, damit Nachrichten zwischen den Instanzen fließen, eine Wiederverbindungslogik im Client samt erneutem Betreten der Räume, und ein Timeout-Konzept über alle Schichten hinweg. Nichts davon ist schwer, aber es summiert sich, und es bleibt dauerhaft an dir hängen.
Wenn du an diesem Punkt bist, steht der Rest im Artikel zum horizontalen Skalieren von Socket.IO.
Die Entscheidungshilfe
In der Reihenfolge durchgehen und beim ersten Treffer aufhören. Die meisten Anwendungen landen bei Punkt eins oder zwei.
- Reicht eine Aktualisierung im Minutenbereich? Dann Polling. Zustandslos, robust, kein Betriebsaufwand.
- Schickt nur der Server, und es soll sofort ankommen? Dann SSE. Wiederverbindung bringt der Browser mit.
- Sendet der Client häufig zurück, oder zählt jede Zehntelsekunde? Dann WebSocket, und plan den Betrieb gleich mit ein.
- Sehr viele Verbindungen bei seltenen Ereignissen? SSE oder Polling skalieren hier günstiger, weil sie keine Sitzung im Speicher halten müssen.
- Müssen Firmennetze mit strengen Proxys durchkommen? Polling zuerst, SSE danach, WebSocket zuletzt.
Häufige Fragen
Ist Long Polling eine sinnvolle Zwischenstufe?
Selten. Es hat die Betriebskosten offener Verbindungen und die Umständlichkeit von HTTP. Wenn du so weit bist, nimm SSE, das löst dasselbe Problem sauberer und wird von allen aktuellen Browsern unterstützt.
Wie viele SSE-Verbindungen verträgt ein Browser?
Über HTTP/1.1 gilt das alte Limit von sechs Verbindungen pro Domain, und SSE zählt mit. Über HTTP/2 fällt das praktisch weg. Wenn ihr noch auf HTTP/1.1 ausliefert, ist das ein echter Stolperstein bei mehreren offenen Tabs.
Kann ich mit SSE auch Daten senden?
Nicht über dieselbe Verbindung, aber du brauchst es meistens auch nicht. Ein normaler POST für die seltenen Schreibvorgänge plus SSE für den Rückkanal ist ein solides Muster und deutlich einfacher zu betreiben als ein WebSocket.
Was ist mit WebTransport oder gRPC-Web?
Beides hat Nischen, in denen es glänzt, und beides bringt Werkzeugketten mit, die zu einem KMU-Projekt selten passen. Für den Regelfall bleiben die drei Verfahren oben die richtige Auswahl.
Dieser Beitrag gibt den Stand von März 2026 wieder und ersetzt keine Rechtsberatung. Für verbindliche Auskünfte zu deinem konkreten Fall wende dich an eine Anwältin oder einen Anwalt.