Eu li um monte de perguntas diferentes sobre qual configuração do Nginx é apropriada para SSE e cheguei a alguns resultados confusos sobre quais configurações usar:
- https://stackoverflow.com/questions/17529421/sending-server-sent-events-through-a-socket-in-c
- https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx
- https://stackoverflow.com/questions/21630509/server-sent-events-connection-timeout-on-node-js-via-nginx
Então, qual é a resposta certa?
Conexão de longa duração
Eventos enviados pelo servidor (SSE) são uma conexão HTTP de longa duração**, portanto, para começar, precisamos disso:
Codificação de transferência em partes
Agora um aparte; As respostas SSE não definem um cabeçalho Content-Length porque não podem saber quantos dados serão enviados, em vez disso, precisam usar o cabeçalho Transfer-Encoding[0][1], o que permite uma conexão de streaming. Observe também: se você não adicionar um Content-Length, a maioria dos servidores HTTP definirá
Transfer-Encoding: chunked;
para você. Estranhamente, o HTTP chunking alertou e causa confusão.A confusão decorre de um aviso um tanto vago na seção Notas da descrição W3 EventSource:
O que levaria alguém a acreditar que
Transfer-Encoding: chunked;
é uma coisa ruim para o SSE. No entanto: este não é necessariamente o caso, é apenas um problema quando seu servidor web está fazendo o agrupamento para você (sem saber informações sobre seus dados). Portanto, embora a maioria das postagens sugira adicionarchunked_transfer_encoding off;
isso, isso não é necessário no caso típico[3].Buffer (o verdadeiro problema)
De onde vem a maioria dos problemas é ter qualquer tipo de buffer entre o servidor de aplicativos e o cliente. Por padrão[4], o Nginx usa
proxy_buffering on
(dê uma olhada tambémuwsgi_buffering
efastcgi_buffering
dependendo do seu aplicativo) e pode optar por armazenar em buffer os pedaços que você deseja enviar ao seu cliente. Isso é ruim porque a natureza em tempo real do SSE é interrompida.No entanto, em vez de ativar
proxy_buffering off
tudo, na verdade é melhor (se você puder) adicionarX-Accel-Buffering: no
como um cabeçalho de resposta no código do servidor de aplicativos para desativar o buffer apenas para a resposta baseada em SSE e não para todas as respostas provenientes de seu aplicativo servidor. Bônus: isso também funcionará parauwsgi
efastcgi
.Solução
E assim as configurações realmente importantes são, na verdade, os cabeçalhos de resposta do servidor de aplicativos:
E potencialmente a implementação de algum mecanismo de ping para que a conexão não fique ociosa por muito tempo. O perigo disso é que o Nginx fechará conexões inativas conforme definido usando a
keepalive
configuração.[0] https://www.rfc-editor.org/rfc/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://www.rfc-editor.org/rfc/rfc7230#section-6.3
[6] https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88