Server-Sent Events vs. WebSockets für REST-API-Echtzeit-Updates
AI generated
{ }
GET
Echtzeit-Updates · SSE vs. WebSocket
Server-Sent Events vs. WebSockets
Welcher Echtzeit-Mechanismus zu welchem REST-API-Anwendungsfall passt, und warum die Wahl selten trivial ist

Sobald eine REST-API Echtzeit-Updates liefern soll, etwa Live-Bestellstatus, Benachrichtigungen oder Preisänderungen, stehen Teams vor der Wahl zwischen Server-Sent Events und WebSockets. Beide lösen das Problem, dass klassisches HTTP-Polling unnötige Latenz und Last erzeugt, unterscheiden sich aber grundlegend in Protokoll-Overhead, Richtung des Datenflusses und der Komplexität der Implementierung, weshalb die Wahl den langfristigen Wartungsaufwand einer API-Erweiterung erheblich beeinflusst.

16 Min. Lesezeit SSE vs. WebSocket Symfony Mercure

1. Warum Polling für Echtzeit-Anforderungen ungeeignet ist

Klassisches HTTP-Polling, bei dem ein Client in festen Intervallen wiederholt nach neuen Daten fragt, erzeugt einen unangenehmen Kompromiss zwischen Latenz und Last: Kurze Intervalle liefern zeitnahe Updates, verursachen aber hohe Serverlast durch überwiegend leere Antworten, während lange Intervalle die Last reduzieren, aber echte Änderungen erst mit spürbarer Verzögerung beim Client ankommen lassen. Für Anwendungsfälle wie Live-Preisänderungen, Chat-Benachrichtigungen oder Bestellstatus-Updates ist diese Verzögerung oft inakzeptabel, insbesondere wenn Nutzer eine sofortige Reaktion der Oberfläche erwarten.

Server-Sent Events und WebSockets lösen dieses Problem, indem der Server aktiv Daten an bereits verbundene Clients sendet (Server Push), statt auf wiederholte Anfragen zu warten. Beide Mechanismen halten eine langlebige Verbindung offen, unterscheiden sich aber grundlegend darin, wie diese Verbindung funktioniert und was über sie übertragen werden kann. Diese grundlegenden Unterschiede wirken sich direkt auf Implementierungsaufwand, Infrastrukturanforderungen und langfristige Wartbarkeit aus, weshalb die Wahl frühzeitig durchdacht werden sollte, statt sie später unter Zeitdruck nachträglich zu korrigieren.

2. Server-Sent Events: einfacher unidirektionaler Server-Push über HTTP

Server-Sent Events (SSE) bauen auf einer normalen, langlebigen HTTP-Verbindung auf, über die der Server kontinuierlich Text-Events im Format text/event-stream an den Client sendet, ohne dass der Client jemals selbst Daten über dieselbe Verbindung zurücksendet. Diese Einfachheit ist ein zentraler Vorteil: SSE funktioniert über normale HTTP-Infrastruktur (Reverse Proxies, Load Balancer, Firewalls), ohne ein Protokoll-Upgrade wie bei WebSockets zu benötigen, und der native EventSource-Browser-API übernimmt Reconnect-Logik bei Verbindungsabbruch automatisch.

Die Kehrseite dieser Einfachheit ist die reine Unidirektionalität: Ein Client, der auf ein empfangenes Event reagieren möchte (etwa eine Chat-Nachricht bestätigen), muss dafür einen separaten, klassischen HTTP-Request an einen anderen Endpoint senden, statt über dieselbe Verbindung zu antworten. Für reine Broadcast-Szenarien, bei denen ausschließlich der Server initiiert, ist das kein Nachteil, für interaktive Echtzeit-Kommunikation dagegen schon.

3. WebSockets: volles bidirektionales Protokoll mit eigenem Overhead

WebSockets starten mit einem HTTP-Upgrade-Handshake, wechseln danach aber vollständig auf ein eigenes, binäres Rahmenprotokoll, über das sowohl Server als auch Client jederzeit Nachrichten in beide Richtungen senden können, ohne dass jede Nachricht wie bei HTTP einen eigenen Request-Response-Zyklus benötigt. Diese echte Bidirektionalität macht WebSockets zur richtigen Wahl für Anwendungsfälle wie Chat-Anwendungen, kollaborative Editoren oder Multiplayer-Interaktionen, bei denen beide Seiten gleichberechtigt kommunizieren müssen.

Dieser Funktionsumfang kommt mit höherer Komplexität: WebSocket-Verbindungen benötigen eigene Reconnect-Logik (die EventSource-API bietet das für SSE nativ, für WebSockets muss sie selbst implementiert werden), eigenes Load-Balancing-Verständnis (klassische Round-Robin-Load-Balancer passen nicht direkt zu langlebigen, zustandsbehafteten Verbindungen) und oft zusätzliche Infrastruktur wie einen dedizierten WebSocket-Server oder einen Hub wie Mercure.


<?php
declare(strict_types=1);

use Symfony\Component\HttpFoundation\StreamedResponse;

final class OrderStatusSseController
{
    public function stream(int $orderId): StreamedResponse
    {
        $response = new StreamedResponse(function () use ($orderId) {
            while (true) {
                $status = $this->orderStatusRepository->getCurrentStatus($orderId);
                echo "data: " . json_encode(['status' => $status]) . "\n\n";
                ob_flush();
                flush();

                if ($status === 'delivered' || connection_aborted()) {
                    break;
                }
                sleep(2);
            }
        });

        $response->headers->set('Content-Type', 'text/event-stream');
        $response->headers->set('Cache-Control', 'no-cache');
        $response->headers->set('X-Accel-Buffering', 'no');
        return $response;
    }
}

4. Die praktische PHP-FPM-Limitierung bei langlebigen Verbindungen

Ein oft unterschätztes praktisches Problem bei SSE und WebSockets in einer klassischen PHP-FPM-Umgebung ist, dass jede offene, langlebige Verbindung einen kompletten PHP-FPM-Worker-Prozess für die gesamte Verbindungsdauer blockiert, was bei tausenden gleichzeitigen Verbindungen die verfügbaren Worker schnell erschöpft. Reine PHP-FPM-Implementierungen von SSE oder WebSockets skalieren deshalb praktisch nur bis zu einer begrenzten Anzahl gleichzeitiger Nutzer.

Für produktive Skalierung wird meist ein dediziertes Echtzeit-Gateway wie Mercure (im Symfony-Ökosystem gut integriert) oder ein separater Node.js-basierter WebSocket-Server eingesetzt, der Verbindungen effizient mit einem event-basierten, nicht-blockierenden Modell verwaltet, statt jede Verbindung an einen vollen PHP-Prozess zu binden. Der PHP-Backend-Code veröffentlicht dann Events an diesen Hub, statt Verbindungen selbst zu halten.

5. Mercure als pragmatischer SSE-Hub im Symfony-Ökosystem

Mercure ist ein offener Standard und ein dediziertes Hub-Programm, das SSE-Verbindungen effizient außerhalb von PHP-FPM verwaltet, während die Symfony-Anwendung lediglich Updates über eine einfache HTTP-API an den Hub publiziert, der sie dann an alle abonnierten Clients verteilt. Dieser Ansatz kombiniert die Einfachheit von SSE auf Client-Seite mit einer produktionsreifen, skalierbaren Infrastruktur auf Server-Seite, ohne dass die Symfony-Anwendung selbst langlebige Verbindungen verwalten muss.

Für WebSocket-basierte Anwendungsfälle existiert kein direkt vergleichbares, ebenso eng ins Symfony-Ökosystem integriertes Standardwerkzeug, weshalb Teams hier häufiger auf externe Lösungen wie Soketi, Pusher oder eine eigene Node.js-basierte Infrastruktur zurückgreifen, was den Integrationsaufwand gegenüber Mercure spürbar erhöht und zusätzliches Betriebswissen im Team erfordert.

6. Konkrete Entscheidungskriterien für die Wahl

Die Entscheidung zwischen SSE und WebSockets sollte primär an der Kommunikationsrichtung ausgerichtet werden: Wenn ausschließlich der Server Updates an Clients pusht, ohne dass Clients über dieselbe Verbindung antworten müssen (Benachrichtigungen, Live-Status, Preisänderungen, Dashboards), ist SSE die einfachere, robustere und mit weniger Infrastrukturaufwand verbundene Wahl. Wenn beide Seiten gleichberechtigt und mit niedriger Latenz kommunizieren müssen (Chat, kollaboratives Editing, Multiplayer), ist WebSocket praktisch alternativlos.

Ein weiteres praktisches Kriterium ist der Umgang mit proxynahen Infrastrukturen: SSE funktioniert zuverlässiger hinter restriktiven Firewalls und Corporate-Proxies, die WebSocket-Upgrades manchmal blockieren, weil SSE als normale, langlebige HTTP-Verbindung erscheint, während WebSocket-Verbindungen explizit als solche erkannt und gegebenenfalls blockiert werden können. Gerade bei B2B-Anwendungen mit Nutzern hinter restriktiven Unternehmensnetzwerken ist dieses Kriterium in der Praxis oft entscheidender als reine technische Eleganz.

7. Hybride Ansätze: REST-API plus SSE oder WebSocket ergänzend

In der Praxis ersetzen SSE und WebSockets die klassische REST-API selten vollständig, sondern ergänzen sie: Zustandsändernde Operationen (Bestellung anlegen, Produkt aktualisieren) laufen weiterhin über klassische REST-Endpoints mit klaren HTTP-Semantiken, während SSE oder WebSocket ausschließlich für die Benachrichtigung über Zustandsänderungen genutzt wird, die anderswo ausgelöst wurden. Diese Trennung hält die REST-API selbst einfach und zustandslos, während die Echtzeit-Schicht als dünne, zusätzliche Kommunikationsebene darüber liegt.

Dieses Muster vermeidet die Versuchung, sämtliche API-Interaktion über WebSocket-Nachrichten neu zu modellieren, was in der Praxis oft zu einer schlechter dokumentierten, schwerer testbaren API führt als eine klare Trennung zwischen zustandsänderndem REST und benachrichtigendem Echtzeit-Kanal. Teams, die diese Trennung konsequent einhalten, profitieren zusätzlich davon, dass bestehende REST-Tooling wie OpenAPI-Dokumentation und Vertragstests weiterhin uneingeschränkt anwendbar bleiben.

8. Heartbeats und Keepalive gegen stille Verbindungsabbrüche

Sowohl SSE- als auch WebSocket-Verbindungen können durch zwischengeschaltete Proxies oder NAT-Gateways nach einer gewissen Inaktivitätszeit stillschweigend geschlossen werden, ohne dass Client oder Server dies sofort bemerken, was zu einer Verbindung führt, die dem Client als offen erscheint, aber tatsächlich tot ist. Regelmäßige Heartbeat-Nachrichten (bei SSE oft simple Kommentarzeilen, bei WebSocket dedizierte Ping/Pong-Frames) halten die Verbindung aktiv und ermöglichen es beiden Seiten, einen stillen Abbruch zeitnah zu erkennen.

Ohne Heartbeat-Mechanismus kann ein Client minutenlang in dem irrigen Glauben verharren, weiterhin aktuelle Updates zu empfangen, obwohl die zugrundeliegende Verbindung längst tot ist, was besonders bei kritischen Echtzeit-Anwendungsfällen wie Preisänderungen zu veralteten, falschen Anzeigen führen kann. Ein sinnvolles Heartbeat-Intervall liegt meist zwischen 15 und 30 Sekunden, ein Kompromiss zwischen frühzeitiger Erkennung und unnötigem zusätzlichem Traffic.

9. SSE und WebSockets im direkten Vergleich

Die folgende Tabelle stellt die wichtigsten Unterschiede gegenüber.

Kriterium Server-Sent Events WebSockets
Richtung Nur Server zu Client Bidirektional
Protokoll Normales HTTP Eigenes Rahmenprotokoll nach Upgrade
Reconnect Automatisch über EventSource-API Muss selbst implementiert werden
Proxy-Kompatibilität Meist unproblematisch Kann von restriktiven Proxies blockiert werden

Mironsoft

OpenAPI-Design, Symfony-APIs und API-Sicherheit

APIs, die externe Teams ohne Rückfragen integrieren können?

Wir prüfen bestehende REST-APIs auf inkonsistente Fehlerformate, fehlende OpenAPI-Dokumentation und Sicherheitslücken und bauen daraus eine API, die klar dokumentiert, versioniert und gegen Missbrauch abgesichert ist.

API-Review

OpenAPI-Spezifikation, Fehlerformate und Statuscodes auf Konsistenz prüfen.

Symfony-Umsetzung

DTOs, Serializer und Validator für saubere, typsichere Request/Response-Modelle einsetzen.

Security-Audit

Rate-Limiting, Auth-Schemes und Input-Validierung gegen echte Angriffsflächen absichern.

10. Zusammenfassung

SSE vs. WebSockets: Das Wichtigste auf einen Blick

SSE für Broadcasts

Einfacher, robuster und mit automatischem Reconnect für reine Server-zu-Client-Updates.

WebSocket für Interaktion

Notwendig, wenn beide Seiten gleichberechtigt und mit niedriger Latenz kommunizieren müssen.

PHP-FPM-Limitierung

Langlebige Verbindungen blockieren FPM-Worker, ein dedizierter Hub wie Mercure ist für Skalierung praktisch nötig.

Ergänzung statt Ersatz

Echtzeit-Kanäle sollten REST für zustandsändernde Operationen ergänzen, nicht komplett ersetzen.

11. FAQ: SSE vs. WebSockets: Das Wichtigste auf einen Blick

1Kann ich SSE auch für bidirektionale Kommunikation nutzen?
Nur mit einem separaten HTTP-Request für die Rückrichtung. Für echte Bidirektionalität über dieselbe Verbindung ist WebSocket erforderlich.
2Unterstützen alle Browser Server-Sent Events?
Ja, alle modernen Browser unterstützen die EventSource-API nativ, mit Ausnahme von Internet Explorer, das keine Rolle mehr spielt.
3Brauche ich zwingend Mercure für SSE in Symfony?
Nein, eine einfache StreamedResponse funktioniert für kleine Nutzerzahlen. Für produktive Skalierung ist ein dedizierter Hub aber praktisch nötig.
4Wie sicher ich SSE- oder WebSocket-Verbindungen gegen unautorisierten Zugriff ab?
Über dieselbe Authentifizierung wie bei REST-Endpoints, etwa ein JWT-Token als Query-Parameter oder im initialen Handshake.
5Was passiert bei einem Verbindungsabbruch mitten in einer WebSocket-Session?
Der Client muss selbst erkennen, dass die Verbindung verloren ging, und eine eigene Reconnect-Logik mit Backoff implementieren.
6Skaliert SSE besser als WebSocket bei vielen gleichzeitigen Nutzern?
Grundsätzlich ähnlich, beide benötigen ein event-basiertes, nicht-blockierendes Backend für echte Skalierung, statt klassischem PHP-FPM.
7Kann ich GraphQL Subscriptions statt SSE oder WebSocket nutzen?
GraphQL Subscriptions laufen technisch meist über WebSocket, sind aber eine höhere Abstraktionsebene für GraphQL-spezifische Anwendungsfälle.
8Wie teste ich SSE- oder WebSocket-Endpoints automatisiert?
Mit dedizierten Test-Clients, die eine Verbindung aufbauen und erwartete Events innerhalb eines Timeouts prüfen, statt klassischer Request-Response-Assertions.
9Ist SSE für mobile Apps geeignet?
Ja, aber mobile Netzwerke mit häufigen Verbindungswechseln profitieren stark vom automatischen Reconnect-Verhalten der EventSource-API.
10Lohnt sich WebSocket für ein einfaches Live-Dashboard?
Meist nicht, wenn das Dashboard nur passiv Daten anzeigt. SSE deckt diesen Anwendungsfall einfacher und mit weniger Infrastruktur ab.