Wenn der Server Neuigkeiten hat
Zwei Arten, einen Push vorzutäuschen
Polling alle zwei Sekunden hat die Anzeigetafel ungefähr eine Sekunde zu spät gelassen und pro Zuschauer 1.800 Anfragen pro Stunde gekostet, fast alle mit “nichts Neues” beantwortet. Beide Kosten haben dieselbe Ursache: Der Server hat die Neuigkeiten, darf aber nur antworten, wenn eine Anfrage wartet. Es gibt zwei bekannte Wege,
Die Anfrage offen halten
Der erste Trick ist Long Polling. Der Zuschauer sendet wie zuvor eine Anfrage, aber der Server antwortet nicht sofort. Er hält die Anfrage offen, bis sich ein Punktestand ändert oder bis seine eigene Wartezeit abläuft, zum Beispiel nach 25 Sekunden. Dann antwortet er, und der Zuschauer sendet sofort die nächste Anfrage.
client server
GET /scores ---->
holds the request
a score changes
<---- 200 OK, the new scores
GET /scores ---->
holds the request
25 seconds pass, no change
<---- 200 OK, nothing new
GET /scores ---->
holds the request
Der Zuschauer fragt, und der Server hält die Anfrage fest. Wenn sich ein Punktestand ändert, antwortet der Server sofort mit dem neuen Punktestand, und der Zuschauer fragt erneut. Wenn 25 ruhige Sekunden vergehen, antwortet der Server, dass sich nichts geändert hat, und der Zuschauer fragt erneut.
Die Verspätung verschwindet fast. Eine Änderung wartet nicht mehr auf die nächste Abfrage, weil fast immer schon eine Anfrage beim Server wartet; meist wartet sie nur darauf, dass die Antwort das Netzwerk durchquert. Etwas länger wartet sie, wenn sie eintrifft, während die vorige Antwort noch unterwegs ist und die nächste Anfrage den Server noch nicht erreicht hat. Auch die leeren Antworten werden weniger: eine pro 25 ruhige Sekunden statt einer alle 2 Sekunden.
Für den Client gibt es eine neue Regel. In HTTP with Python hast du jeder Anfrage ein Timeout gegeben und gelernt, dass ein Timeout bedeutet, dass dein Client beschließt, nicht länger zu warten, und nicht, dass der Server versagt hat. Ein Long Poll ist eine Anfrage, die warten soll, also muss das Timeout des Clients länger sein als die Haltezeit des Servers. Sonst gibt der Client bei jeder ruhigen Phase auf, kurz bevor das ehrliche “nichts Neues” des Servers eintrifft.
Der Server hält einen Long Poll bis zu 25 Sekunden lang. Welches Client-Timeout ist sinnvoll?
Eine Antwort, die nie endet
Der zweite Trick geht weiter: eine Anfrage und eine Antwort, die nie fertig wird. Das sind Server-Sent Events, oft mit SSE abgekürzt. Der Zuschauer sendet ein einziges GET, und der Server antwortet mit einem Kopf, dessen Content-Type text/event-stream ist:
HTTP/1.1 200 OK
Content-Type: text/event-stream
Transfer-Encoding: chunked
Der Kopf hat keine Content-Length, weil der Server nicht weiß, wie lang der Body wird. Er sendet den Body in Chunks, eine der drei Arten, wie ein Body enden kann, die du in HTTP with Python kennengelernt hast, und er hält die Verbindung offen. Jedes Mal, wenn sich ein Punktestand ändert, schreibt der Server ein weiteres Event in den Body. Ohne die Chunk-Größen sieht der Body, den der Zuschauer liest, so aus:
data: Owls 12
data: Herons 9
Jedes Event ist eine data:-Zeile, gefolgt von einer Leerzeile. Die Leerzeile beendet ein Event; ein Event darf vor ihr mehrere data:-Zeilen haben. Die Daten hier sind einfacher Text, aber sie können alles sein, was in eine Zeile passt, auch
Um Events aus diesem Text zu lesen, brauchst du nur die Werkzeuge, die du schon hast. Dieser Block arbeitet mit demselben Text, geschrieben als ein einziges
Er gibt Owls 12 und dann Herons 9 aus. Das Aufteilen bei "\n\n", der Leerzeile zwischen Events, ergibt ein Stück pro Event, plus einen leeren String nach dem letzten, weil der Stream mit einer Leerzeile endet. Das data: beginnt, also auch diesen leeren String, und der event[6:] entfernt die sechs Zeichen von data: am Anfang.
Ein Browser hat dieses Lesen eingebaut, und er öffnet einen abgebrochenen Stream auch wieder. Auf der Serverseite ist ein Event-Stream eine gewöhnliche HTTP-Antwort, er braucht also nichts, was HTTP nicht schon hat.
Was beendet in einem Event-Stream ein Event?
Was jede Technik behält
Jeder Trick beseitigt eine Ursache der Kosten des Pollings und behält eine Grenze.
| Technik | Was sie beseitigt | Was sie behält |
|---|---|---|
| Long Polling | das Warten auf die nächste Abfrage und die meisten leeren Antworten | eine Anfrage für jede Neuigkeit, und der Client beginnt immer noch jeden Austausch |
| Server-Sent Events | die Anfrage für jede Neuigkeit: eine Antwort trägt alle | nur eine Richtung, vom Server zum Client |
Beim Long Polling kann der Server nur auf eine Anfrage antworten, also beendet jede Änderung des Punktestands immer noch eine Anfrage und verlangt, dass der Zuschauer eine weitere sendet. Bei SSE schreibt der Server, wann er will, aber nur der Server schreibt. Der Zuschauer kann auf dem Event-Stream nichts zurücksenden.
Das ist für die Anzeigetafel wichtig, weil auch der Punktezähler etwas zu sagen hat. Bei SSE empfängt ein Zuschauer den Punktestand auf dem Stream, aber der neue Punktestand des Punktezählers muss einen anderen Weg nehmen.
Wie sendet der Punktezähler bei Server-Sent Events einen neuen Punktestand an den Server?
Die Bausteine gibt es also: eine Anfrage, die der Server festhalten kann, und eine Antwort, die weiter Neuigkeiten trägt. Was fehlt, ist eine Verbindung, auf der beide Seiten sprechen dürfen, wann immer sie wollen. Die nächste Lektion zählt genau auf, was eine solche Verbindung bieten muss.