Conexão de longa duração
O Server-Sent Events (SSE) é uma conexão HTTP de longa duração **, portanto, para começar, precisamos disso:
proxy_http_version 1.1;
proxy_set_header Connection "";
NOTE: TCP connections in HTTP/1.1 are persistent by default, so setting the Connection header to empty does the right thing and is the Nginx suggestion.
Codificação de transferência em partes
Agora um aparte; Respostas SSE não definem um cabeçalho Content-Length porque elas não podem saber quantos dados
será enviado, em vez disso, eles 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 chunk HTTP alertou e causa confusão.
A confusão vem de um aviso um pouco vago na seção Notas da descrição do W3 EventSource:
Authors are also cautioned that HTTP chunking can have unexpected negative effects on the reliability of this protocol. Where possible, chunking should be disabled for serving event streams unless the rate of messages is high enough for this not to matter.
O que levaria a pessoa a acreditar que Transfer-Encoding: chunked;
é uma coisa ruim para a SSE. No entanto: isso não é necessariamente o caso, é apenas um problema quando o seu servidor está fazendo o chunking para você (não sabendo informações sobre seus dados). Então, enquanto a maioria das postagens sugere adicionar chunked_transfer_encoding off;
, isso não é necessário no caso típico [3].
Buffer (o problema real)
A maioria dos problemas vem de qualquer tipo de buffer entre o servidor de aplicativos e o cliente. Por padrão [4], o Nginx usa
proxy_buffering on
(também dê uma olhada em uwsgi_buffering
e fastcgi_buffering
dependendo da sua aplicação)
e pode optar por armazenar em buffer os blocos que você deseja obter para o seu cliente. Isso é uma coisa ruim porque o
natureza em tempo real das quebras de SSE.
No entanto, em vez de transformar proxy_buffering off
para tudo, é realmente
melhor (se puder) adicionar o X-Accel-Buffering: no
como cabeçalho de resposta no código do servidor de aplicativos
para desativar apenas o armazenamento em buffer para a resposta baseada em SSE e não para todas as respostas provenientes do seu servidor de aplicativos. Bônus: isso também funcionará para uwsgi
e fastcgi
.
Solução
Assim, as configurações realmente importantes são, na verdade, os cabeçalhos de resposta do servidor de aplicativos:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
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á as conexões inativas conforme definido usando a configuração keepalive
.
[0] link
[1] link
[2] link
[3] link
[4] link
[5] link
[6] link