Para eventos enviados pelo servidor (SSE), que configuração de proxy do Nginx é apropriada?


20

Eu li várias perguntas diferentes sobre qual configuração do Nginx é apropriada para o SSE e obtive alguns resultados confusos sobre as configurações a serem usadas:

Então, qual é a resposta certa?

Respostas:


44

Conexão de longa duração

Eventos enviados pelo servidor (SSE) são uma conexão HTTP de execução longa **, portanto, para iniciantes, precisamos do seguinte:

proxy_http_version 1.1;
proxy_set_header Connection "";

NOTA: As conexões TCP no HTTP / 1.1 são persistentes por padrão, portanto, definir o cabeçalho de conexão como vazio faz a coisa certa e é a sugestão do Nginx.

Codificação de transferência em pedaços

Agora um aparte; As respostas SSE não definem um cabeçalho de comprimento de conteúdo porque não podem saber quantos dados serão enviados; eles precisam usar o cabeçalho de codificação de transferência [0] [1], o que permite uma conexão de streaming. Observe também: se você não adicionar um Comprimento de conteúdo, a maioria dos servidores HTTP definirá Transfer-Encoding: chunked;para você. Estranhamente, o chunking HTTP alertou e causa confusão.

A confusão decorre de um aviso um tanto vago na seção Notas da descrição W3 EventSource:

Os autores também são alertados que o HTTP chunking pode ter efeitos negativos inesperados na confiabilidade deste protocolo. Sempre que possível, o chunking deve ser desativado para veicular fluxos de eventos, a menos que a taxa de mensagens seja alta o suficiente para que isso não importe.

O que levaria a acreditar que Transfer-Encoding: chunked;é uma coisa ruim para a SSE. No entanto: esse não é necessariamente o caso, é apenas um problema quando seu servidor da web faz o trabalho por você (sem saber informações sobre seus dados). Portanto, embora a maioria das postagens sugira que chunked_transfer_encoding off;isso não seja necessário no caso típico [3].

Buffer (o verdadeiro problema)

A origem da 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(também dê uma olhada uwsgi_bufferinge fastcgi_bufferingdependendo 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 procurar proxy_buffering offpor tudo, é realmente melhor (se você puder) adicionar o X-Accel-Buffering: nocabeçalho como 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 do seu aplicativo servidor. Bônus: isso também funcionará para uwsgie fastcgi.

Solução

E, portanto, 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 keepaliveconfiguração.


[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


Você pode elaborar qual é o mecanismo de ping? É simplesmente enviar uma mensagem vazia para o canal? Eu configurei os cabeçalhos de nível do nginx e do aplicativo, mas ainda estou recebendo um tempo limite 504 do nginx para qualquer um dos pontos de extremidade da origem de eventos.
— wgwz

um ping seria apenas alguns dados (falsos) enviados em um intervalo através da conexão; no cliente, você pode manipular esse ping e ignorá-lo. NOTA: se a sua conexão não estiver funcionando, o ping não ajudará, algo está errado.
— C4urself

2
Eu adicionei os cabeçalhos de resposta conforme sugerido e funciona. Não fiz alterações na configuração do nginx v1.12 e até agora não há problemas.
— Mikkel

11
Adicionar o X-Accel-Buffering: nocabeçalho foi a chave para mim, mas o mais importante foi que o @ c4urself escreveu: "adicione o X-Accel-Buffering: no como um cabeçalho de resposta no código do servidor de aplicativos ". A adição desse cabeçalho a uma seção de localização em minha configuração do nginx não funcionou - todo o fluxo de eventos aguardou o envio até depois que o aplicativo foi concluído / finalizado.
— MDMower 17/01/19

É proxy_http_version 1.1; necessário? Estou tentando executar mais de 6 fluxos SSE de um navegador e, portanto, preciso de HTTP2.
— Bilal Fazlani 11/07/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.