Długotrwałe połączenie
Zdarzenia wysyłane przez serwer (SSE) to długotrwałe połączenie HTTP **, więc na początek potrzebujemy tego:
proxy_http_version 1.1;
proxy_set_header Connection "";
UWAGA: Połączenia TCP w HTTP / 1.1 są domyślnie trwałe, więc ustawienie pustego nagłówka połączenia robi właściwą rzecz i jest sugestią Nginx.
Chunked Transfer-Encoding
Teraz na bok; Odpowiedzi SSE nie ustawiają nagłówka Content-Length, ponieważ nie mogą wiedzieć, ile danych zostanie wysłanych, zamiast tego muszą użyć nagłówka Transfer-Encoding [0] [1], co pozwala na połączenie strumieniowe. Uwaga: jeśli nie dodasz długości treści, większość serwerów HTTP zostanie Transfer-Encoding: chunked;
dla Ciebie ustawiona . O dziwo, fragmentowanie HTTP ostrzegało i powoduje zamieszanie.
Zamieszanie wynika z nieco niejasnego ostrzeżenia w sekcji Notatki opisu W3 EventSource:
Ostrzega się także autorów, że dzielenie HTTP może mieć nieoczekiwany negatywny wpływ na niezawodność tego protokołu. Tam, gdzie to możliwe, dzielenie na fragmenty powinno być wyłączone w celu obsługi strumieni zdarzeń, chyba że szybkość wiadomości jest wystarczająco wysoka, aby nie miało to znaczenia.
Co mogłoby prowadzić do przekonania, że Transfer-Encoding: chunked;
jest to złe dla SSE. Jednak: niekoniecznie tak jest, jest to tylko problem, gdy twój serwer wykonuje za ciebie części (nie znając informacji o twoich danych). Chociaż większość postów sugeruje, że dodanie chunked_transfer_encoding off;
tego nie jest konieczne w typowym przypadku [3].
Buforowanie (prawdziwy problem)
Większość problemów wynika z buforowania między serwerem aplikacji a klientem. Domyślnie [4], wykorzystuje nginx
proxy_buffering on
(również przyjrzeć uwsgi_buffering
i fastcgi_buffering
w zależności od aplikacji), a może zdecydować się na kawałki buforować że chcesz wyjść do klienta. Jest to zła rzecz, ponieważ psuje się charakter SSE w czasie rzeczywistym.
Jednak zamiast zwracać się proxy_buffering off
o wszystko, najlepiej jest (jeśli możesz) dodać X-Accel-Buffering: no
nagłówek odpowiedzi w kodzie serwera aplikacji, aby wyłączyć buforowanie tylko dla odpowiedzi opartej na SSE, a nie dla wszystkich odpowiedzi pochodzących z aplikacji serwer. Bonus: będzie to również działać dla uwsgi
i fastcgi
.
Rozwiązanie
Tak więc naprawdę ważnymi ustawieniami są nagłówki odpowiedzi serwera aplikacji:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
I potencjalnie implementacja jakiegoś mechanizmu pingowania, aby połączenie nie pozostawało zbyt długo bezczynne. Niebezpieczeństwo polega na tym, że Nginx zamyka bezczynne połączenia zgodnie z keepalive
ustawieniem.
[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
nagłówka było dla mnie kluczowe, ale co ważne, musiałem zrobić tak, jak napisał @ c4urself: „dodaj buforowanie X-Accel: nie jako nagłówek odpowiedzi w kodzie serwera aplikacji ”. Dodanie tego nagłówka do sekcji lokalizacji w mojej konfiguracji nginx nie zadziałało - cały strumień zdarzeń czekał na wysłanie aż do zakończenia / zakończenia aplikacji.proxy_http_version 1.1;
konieczne? Próbuję uruchomić więcej niż 6 strumieni SSE z przeglądarki i dlatego potrzebuję HTTP2.