11 Punkte von GN⁺ 2025-04-13 | 3 Kommentare | Auf WhatsApp teilen
  • WebSocket ist für Echtzeitkommunikation nützlich, aber nicht immer erforderlich; HTTP-basierte Alternativen können einfacher und stabiler sein
  • Bei Transaktionsverarbeitung, Verbindungsmanagement und Serverkomplexität kann WebSocket unnötigen Overhead verursachen
  • Mit HTTP Streaming und der Bibliothek eventkit sind Echtzeit-Synchronisierung und Event-Verarbeitung auch ohne WebSocket möglich

Was ist WebSocket?

  • WebSocket ist eine Technologie, die einen persistenten bidirektionalen Kommunikationskanal zwischen Client und Server öffnet
  • Die Verbindung wird über HTTP gestartet, danach erfolgt die Kommunikation jedoch über ein separates Protokoll
  • Sie wird häufig zur Umsetzung von Echtzeit-Anwendungen eingesetzt und ist nützlich, weil sie beidseitige Kommunikation ermöglicht

WebSocket-Nachrichten sind nicht transaktionsbasiert

  • WebSocket garantiert keine direkte Zuordnung zwischen Anfrage und Antwort
  • Befehle zur Statusänderung und die zugehörigen Ergebnisnachrichten können vermischt im selben Stream eintreffen
  • Wenn zum Beispiel ein Client einen Status ändert und ein Fehler auftritt, ist schwer zu erkennen, zu welchem Befehl der Fehler gehört
  • Eine Lösung besteht darin, requestId einzuschließen, um Befehl und Antwort zu verknüpfen, aber das erhöht Komplexität und Verwaltungsaufwand
  • Einfacher ist es, Befehle transaktionsbasiert über HTTP zu senden und WebSocket nur für das Broadcasting von Statusänderungen zu verwenden
  • Senden und Empfangen lassen sich trennen: die Sendeseite über HTTP-Anfragen, die Empfangsseite über WebSocket oder ein anderes Streaming-Verfahren

Die Schwierigkeiten beim Verwalten des WebSocket-Verbindungslebenszyklus

  • Bei WebSocket müssen Start, Ende, Fehler und Wiederverbindung der Verbindung direkt behandelt werden
  • Die grundlegende Verarbeitung im Browser umfasst typischerweise das Behandeln von Ereignissen wie Verbindungsaufbau, Nachrichteneingang, Fehlern und Verbindungsende
  • Zusätzliche Logik wie Reconnect-Mechanismen, Nachrichtenpufferung und exponentielles Backoff ist erforderlich
  • HTTP ist dagegen einfacher zu implementieren, weil Beginn und Ende pro Anfrage klar definiert sind
  • Das komplexe Lebenszyklusmanagement ist nur dann gerechtfertigt, wenn es einen klaren Grund für den Einsatz von WebSocket gibt

Mehr Komplexität im Server-Code

  • WebSocket muss HTTP-Upgrade-Anfragen verarbeiten, was zusätzliche Handshake-Logik erfordert
  • Spezielle Header wie Sec-WebSocket-Key müssen validiert und passende Response-Header zurückgegeben werden
  • Nach dem Aufbau der WebSocket-Verbindung muss ein dauerhafter Zustand für eingehende und ausgehende Nachrichten verwaltet werden; zudem können Probleme wie die Verarbeitung partieller Frames auftreten
  • Debugging und Fehlerbehandlung sind schwieriger als bei einer reinen HTTP-Lösung
  • Frameworks abstrahieren zwar einen Teil davon, aber die grundlegende Komplexität bleibt bestehen

Alternative: HTTP Streaming

  • HTTP unterstützt Streaming von Haus aus; statt einer kompletten Datei kann ein Datenstrom in Echtzeit übertragen werden
  • Die Empfangsseite eines klassischen WebSocket-Setups kann vollständig durch HTTP Streaming ersetzt werden
  • Mit asynchronen Generatoren lassen sich Status-Updates als Stream verarbeiten
  • Ablauf auf der Serverseite
    • Status-Updates werden in der Funktion zur Befehlsverarbeitung durchgeführt
    • Verbundene Clients erhalten über Generatoren jedes Mal neue Werte, wenn diese verfügbar sind
    • Befehle zur Statusänderung werden per HTTP POST gesendet, der Echtzeit-Stream wird über eine GET-Anfrage abonniert
  • Ablauf auf der Client-Seite
    • Echtzeitdaten werden über die Fetch API und einen Stream Reader empfangen
    • Nach dem Dekodieren des Textes wird die UI aktualisiert
  • Mit dieser Struktur lässt sich Echtzeit-Synchronisierung auch ohne WebSocket umsetzen

Bonus: Einführung in die Bibliothek eventkit

  • eventkit ist eine Bibliothek, mit der sich asynchrone Streams einfach aufbauen und beobachten lassen
  • Sie ähnelt RxJS, bietet aber ein verbessertes Nebenwirkungsmanagement und ist generatorbasiert entworfen
  • Wenn Status-Updates in den Stream gepusht werden, können Clients diese in Echtzeit empfangen
  • Mit Stream und AsyncObservable lässt sich die Implementierung auf Server- und Client-Seite einfach halten
  • Einsatz von eventkit auf der Serverseite
    • Statusänderungen werden in einen Stream gepusht, den die Clients abonnieren
  • Einsatz von eventkit auf der Client-Seite
    • Stream-Daten werden empfangen, dekodiert und anschließend zur Aktualisierung der UI verwendet
  • Es gibt außerdem ein offizielles GitHub-Repository und eine Anleitung zu HTTP Streaming

GitHub: https://github.com/hntrl/eventkit

3 Kommentare

 
[Dieser Kommentar wurde ausgeblendet.]
 
[Dieser Kommentar wurde ausgeblendet.]
 
GN⁺ 2025-04-13
Hacker-News-Kommentare
  • Ich glaube nicht, dass HTTP-Streaming für dieses Muster konzipiert wurde. HTTP-Streaming ist dafür gedacht, große Datenmengen in Teile zu zerlegen. Wenn man Streaming wie einen Pub/Sub-Mechanismus verwendet, könnte man es bereuen. HTTP-Zwischenstationen erwarten dieses Traffic-Muster nicht (NGINX, CloudFlare usw.). Jedes Mal, wenn die WLAN-Verbindung abbricht, wird die Fetch-API wahrscheinlich einen Fehler wegen eines fehlgeschlagenen Requests auslösen

    • In vielen Fällen braucht man keine WebSockets. Server-Sent Events (SSE) sind die einfachere Lösung. Schade, dass SSE so wenig Beachtung gefunden hat
  • Eine RequestID an den Server zu senden, um einen Request/Response-Zyklus zu erhalten, ist weder seltsam noch übertrieben. In ernsthaften Apps ist eine API wie send(message).then(res => ...) immer wertvoll

    • Upgrade-Requests sind verwirrend. Es ist lästig, dass WebSocket-Server in HTTP-Server eingebettet werden und nicht integriert sind
    • Statt Middleware wiederzuverwenden, die in einem WebSocket-Request headers['authorization'] liest, muss man auf ein connectionParams-Objekt zugreifen, das so tut, als wären es Request-Header
    • Die WebSocket-Browser-API ist angenehmer zu handhaben als EventSource
  • Beim Video-Streaming fordert der Client Chunks per Range an, nicht über eine einzelne HTTP-Verbindung

  • Es ist besser, SSE statt EventKit zu verwenden

  • Im POC werde ich traditionelle HTTP-Formularübermittlungen verwenden. Mehr braucht es nicht

    • Der Architekt behauptet, dass WebSockets notwendig seien
    • Für den POC braucht man weder XHR noch WebSockets. Es ist ein sequentieller Kauf-Workflow
    • Am Ende liefert man unnötige WebSockets aus
  • Das Problem bei HTTP2 ist, dass Server Push auf ein bestehendes Protokoll aufgesetzt wurde. HTTP ist ein Protokoll zur Ressourcenübertragung und fügt unnötigen Overhead hinzu. Der Hauptzweck von HTTP2 ist, dass der Server Dateien/Ressourcen proaktiv an den Client pusht, um Round-Trip-Latenz zu reduzieren

    • WebSockets sind ein einfacheres Protokoll, das für bidirektionale Kommunikation entworfen wurde. Mit einer einzelnen Verbindung lässt sich der Datenfluss leichter steuern. Zustandsverwaltung und Wiederherstellung nach Verbindungsverlust sind einfacher. Authentifizierung und Zugriffskontrolle werden unkomplizierter
  • WebSockets senden nicht als Stream, sondern als Datagramme (Pakete). Die WebSockets-API von JavaScript-Bibliotheken kann keinen Backpressure verarbeiten und nicht alle Fehler behandeln. Wenn man sie wie einen TCP-Stream verwenden will, muss man vorsichtig sein

  • Ich habe es bereut, WebSockets in Produktion ausgerollt zu haben. Es gab Probleme wie NGINX, das Verbindungen nach 4/8 Stunden beendet, und Browser, die nach dem Ruhezustand keine Wiederverbindung herstellen. Wenn möglich, sollte man WebSockets und langlebige Verbindungen vermeiden

  • Es gibt eine idealisierte Wahrnehmung von WebSockets. Man neigt dazu, WebSockets für Streaming-/Echtzeit-Anwendungsfälle einzusetzen. WebSockets verlieren die Einfachheit und die Vorteile der HTTP-Werkzeuge. Die Lösung für Streaming-Server-Änderungen sind h2/h3 und SSE. Wenn man pro Client auf maximal 0,5 req/s bündeln kann, braucht man keine WebSockets

  • Wer sich für HTTP-Streaming interessiert, sollte sich Braid-HTTP ansehen. Es erweitert HTTP elegant um Event-Streaming und bietet ein leistungsfähiges Protokoll zur Synchronisierung von Zuständen