Per Server-Sent Events (SSE) quale configurazione proxy Nginx è appropriata?


Risposte:


45

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_bufferinge in fastcgi_bufferingbase 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 offper tutto, in realtà è meglio (se sei in grado) di aggiungere l' X-Accel-Buffering: nointestazione 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 uwsgie 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' keepaliveimpostazione.


[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


Puoi approfondire qual è il meccanismo del ping? Sta semplicemente inviando un messaggio vuoto al canale? Ho impostato le intestazioni a livello di app e nginx ma sto ancora ricevendo un timeout 504 da nginx per uno qualsiasi degli endpoint di origine degli eventi.
wgwz,

un ping sarebbe solo alcuni dati (fasulli) inviati a intervalli sulla connessione, sul client è possibile gestire questo ping e ignorarlo. NOTA: se la connessione non funziona affatto, il ping non aiuta, qualcos'altro non va.
c4urself

2
Ho aggiunto le intestazioni di risposta come suggerito e funziona. Non ho apportato modifiche alla configurazione nginx v1.12 e finora nessun problema.
Mikkel,

1
L'aggiunta X-Accel-Buffering: nodell'intestazione è stata la chiave per me, ma soprattutto, ho dovuto fare come @ c4urself ha scritto: "aggiungi X-Accel-Buffering: no come intestazione di risposta nel codice del server delle applicazioni ". L'aggiunta di questa intestazione a una sezione di posizione nella mia configurazione di nginx non ha funzionato: l'intero flusso di eventi ha atteso di essere inviato fino a quando l'applicazione non era terminata / terminata.
MDMower

È proxy_http_version 1.1; necessario? Sto cercando di eseguire più di 6 stream SSE da un browser e quindi ho bisogno di HTTP2.
Bilal Fazlani,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.