it-swarm.com.de

Welche Nginx-Proxy-Konfiguration ist für Server-Sent Events (SSE) geeignet?

Ich habe eine Reihe verschiedener Fragen dazu gelesen, für welche Nginx-Konfiguration SSE] geeignet ist, und einige verwirrende Ergebnisse hinsichtlich der zu verwendenden Einstellungen erzielt:

Was ist die richtige Antwort?

23
c4urself

Langjährige Verbindung

Server-Sent Events (SSE) sind eine lang laufende HTTP-Verbindung **. Für den Anfang benötigen wir Folgendes:

proxy_http_version 1.1;
proxy_set_header Connection "";

HINWEIS: 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

Nun beiseite; SSE Antworten setzen keinen Content-Length-Header, da sie nicht wissen können, wie viele Daten gesendet werden. Stattdessen müssen sie den Transfer-Encoding-Header [0] [1] verwenden, was dies zulässt Beachten Sie auch: Wenn Sie keine Inhaltslänge hinzufügen, setzen die meisten HTTP-Server Transfer-Encoding: chunked; für Sie. Seltsamerweise warnt HTTP-Chunking davor und führt zu Verwirrung.

Die Verwirrung ergibt sich aus einer etwas vagen Warnung im Abschnitt "Notizen" der W3 EventSource-Beschreibung:

Die 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 dazu führen würde, dass man glaubt, dass Transfer-Encoding: chunked; eine schlechte Sache für SSE ist. Dies ist jedoch nicht unbedingt der Fall, sondern nur dann ein Problem, wenn Ihr Webserver das Chunking für Sie ausführt (ohne Informationen über Ihre Daten zu kennen). Während die meisten Beiträge das Hinzufügen von chunked_transfer_encoding off; vorschlagen, ist dies im typischen Fall nicht erforderlich [3].

Pufferung (das eigentliche Problem)

Die meisten Probleme entstehen durch 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 kann die von Ihnen verwendeten Chunks puffern möchte zu Ihrem Kunden raus. Dies ist eine schlechte Sache, da die Echtzeitnatur von SSE bricht).

Anstatt jedoch proxy_buffering off für alles zu aktivieren, ist es am besten (wenn Sie können), den X-Accel-Buffering: no als Antwortheader in Ihren Anwendungsservercode einzufügen, um nur die Pufferung zu deaktivieren für die SSE-basierte Antwort und nicht für alle Antworten, die von Ihrem App-Server kommen. Bonus: Dies funktioniert auch für uwsgi und fastcgi.

Lösung

Die wirklich wichtigen Einstellungen sind also die App-Server-Antwortheader:

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 Einstellung keepalive 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.
[6] https://Gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88

49
c4urself