Langfristige Verbindung
Server-Sent Events (SSE) sind eine lang laufende HTTP-Verbindung **. Für den Anfang benötigen wir also Folgendes:
proxy_http_version 1.1;
proxy_set_header Connection "";
ANMERKUNG: TCP-Verbindungen in HTTP / 1.1 sind standardmäßig persistent. Wenn Sie also den Verbindungsheader auf leer setzen, ist dies das Richtige und der Nginx-Vorschlag.
Chunked Transfer-Encoding
Jetzt beiseite; SSE-Antworten legen keinen Content-Length-Header fest, da sie nicht wissen können, wie viele Daten gesendet werden, sondern stattdessen den Transfer-Encoding-Header [0] [1] verwenden müssen, der eine Streaming-Verbindung ermöglicht. Beachten Sie auch: Wenn Sie keine Inhaltslänge hinzufügen, werden die meisten HTTP-Server Transfer-Encoding: chunked;
für Sie eingerichtet. Seltsamerweise warnt HTTP-Chunking vor und sorgt für Verwirrung.
Die Verwirrung rührt von einer etwas vagen Warnung im Abschnitt "Notizen" der W3 EventSource-Beschreibung her:
Autoren werden auch darauf hingewiesen, dass HTTP-Chunking unerwartete negative Auswirkungen auf die Zuverlässigkeit dieses Protokolls haben kann. Wenn möglich, sollte das Chunking für die Bereitstellung von Ereignisströmen deaktiviert werden, es sei denn, die Nachrichtenrate ist hoch genug, damit dies keine Rolle spielt.
Was zu der Annahme führen würde, dass dies Transfer-Encoding: chunked;
eine schlechte Sache für SSE ist. Dies ist jedoch nicht unbedingt der Fall, es ist nur ein Problem, wenn Ihr Webserver das Chunking für Sie durchführt (ohne Informationen über Ihre Daten zu kennen). Während die meisten Posts vorschlagen, dass chunked_transfer_encoding off;
dies im typischen Fall nicht erforderlich ist [3].
Pufferung (das eigentliche Problem)
Wo die meisten Probleme herkommen, ist eine Art Pufferung zwischen dem App-Server und dem Client. Standardmäßig [4] verwendet Nginx
proxy_buffering on
(siehe auch uwsgi_buffering
und fastcgi_buffering
abhängig von Ihrer Anwendung) und puffert möglicherweise die Chunks, die Sie an Ihren Client senden möchten. Dies ist eine schlechte Sache, da der Echtzeitcharakter von SSE bricht.
Anstatt proxy_buffering off
für alles zu drehen , ist es jedoch am besten (wenn Sie dazu in der Lage sind), den X-Accel-Buffering: no
Header als Antwort in Ihren Anwendungsserver-Code einzufügen, um die Pufferung nur für die SSE-basierte Antwort und nicht für alle Antworten aus Ihrer App zu deaktivieren Server. Bonus: Dies funktioniert auch für uwsgi
und fastcgi
.
Lösung
Die wirklich wichtigen Einstellungen sind also die Antwort-Header des App-Servers:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
Und möglicherweise die Implementierung eines Ping-Mechanismus, damit die Verbindung nicht zu lange inaktiv bleibt. Die Gefahr besteht darin, dass Nginx Leerlaufverbindungen schließt, wie mit der keepalive
Einstellung festgelegt.
[0] https://tools.ietf.org/html/rfc2616#section-3.6
[1] https://en.wikipedia.org/wiki/Chunked_transfer_encoding
[2] https://www.w3.org/TR / 2009 / WD-eventsource-20091029 / # text-event-stream
[3] https://github.com/whatwg/html/issues/515
[4] http://nginx.org/en/docs/http/ ngx_http_proxy_module.html # proxy_buffering
[5] https://tools.ietf.org/html/rfc7230#section-6.3
[6] https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88
X-Accel-Buffering: no
Kopfes war der Schlüssel für mich, aber wichtiger ist , was ich tun musste , wie @ c4urself schrieb: „fügen Sie das X-Accel-Buffering: Nein als Antwort - Header in Ihrem Anwendungsserver - Code “. Das Hinzufügen dieses Headers zu einem Speicherortabschnitt in meiner Nginx-Konfiguration funktionierte nicht - der gesamte Ereignisstrom wartete darauf, gesendet zu werden, bis die Anwendung beendet / beendet wurde.proxy_http_version 1.1;
notwendig Ich versuche, mehr als 6 SSE-Streams über einen Browser auszuführen, und benötige daher HTTP2.