Connessione a lungo termine
Gli Server-Sent Events (SSE) sono una connessione HTTP di lunga durata **, quindi per cominciare abbiamo bisogno di questo:
proxy_http_version 1.1;
proxy_set_header Connection "";
NOTA: le connessioni TCP in HTTP / 1.1 sono persistenti per impostazione predefinita, quindi impostare l'intestazione Connessione su vuoto fa la cosa giusta ed è il suggerimento di Nginx.
Chunked Transfer-Encoding
Adesso a parte; Le risposte SSE non impostano un'intestazione Content-Length perché non possono sapere quanti dati verranno inviati, ma devono utilizzare l'intestazione Transfer-Encoding [0] [1], che consente una connessione di streaming. Nota anche: se non aggiungi una lunghezza del contenuto, la maggior parte dei server HTTP verrà impostata Transfer-Encoding: chunked;
per te. Stranamente, il blocco HTTP ha messo in guardia e provoca confusione.
La confusione deriva da un avvertimento piuttosto vago nella sezione Note della descrizione di EventSource W3:
Gli autori sono inoltre avvisati che il blocco HTTP può avere effetti negativi imprevisti sull'affidabilità di questo protocollo. Laddove possibile, la suddivisione in blocchi dovrebbe essere disabilitata per servire i flussi di eventi a meno che la frequenza dei messaggi sia abbastanza alta da non importare.
Il che porterebbe a credere che Transfer-Encoding: chunked;
sia una cosa negativa per SSE. Tuttavia: questo non è necessariamente il caso, è solo un problema quando il tuo server web sta eseguendo il chunking per te (non conoscendo le informazioni sui tuoi dati). Quindi, mentre la maggior parte dei post suggerirà di aggiungere chunked_transfer_encoding off;
questo non è necessario nel caso tipico [3].
Buffering (il vero problema)
La maggior parte dei problemi proviene da qualsiasi tipo di buffering tra il server delle app e il client. Per impostazione predefinita [4], Nginx utilizza
proxy_buffering on
(anche dare un'occhiata uwsgi_buffering
e in fastcgi_buffering
base alla propria applicazione) e può scegliere di bufferizzare i blocchi che si desidera distribuire al proprio client. Questa è una cosa negativa perché la natura in tempo reale delle SSE si interrompe.
Tuttavia, invece di girare proxy_buffering off
per tutto, in realtà è meglio (se sei in grado) di aggiungere l' X-Accel-Buffering: no
intestazione di risposta nel codice del server delle applicazioni per disattivare il buffering solo per la risposta basata su SSE e non per tutte le risposte provenienti dalla tua app server. Bonus: questo funzionerà anche per uwsgi
e fastcgi
.
Soluzione
E quindi le impostazioni davvero importanti sono in realtà le intestazioni di risposta del server delle app:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
E potenzialmente l'implementazione di alcuni meccanismi di ping in modo che la connessione non rimanga inattiva per troppo tempo. Il pericolo è che Nginx chiuderà le connessioni inattive come impostato usando l' keepalive
impostazione.
[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