Conexión de larga duración
Los eventos enviados por el servidor (SSE) son una conexión HTTP de larga duración **, por lo que para empezar necesitamos esto:
proxy_http_version 1.1;
proxy_set_header Connection "";
NOTA: Las conexiones TCP en HTTP / 1.1 son persistentes de manera predeterminada, por lo que configurar el encabezado de la conexión en vacío hace lo correcto y es la sugerencia de Nginx.
Transferencia-codificación fragmentada
Ahora un aparte; Las respuestas SSE no establecen un encabezado Content-Length porque no pueden saber cuántos datos se enviarán, sino que necesitan usar el encabezado Transfer-Encoding [0] [1], lo que permite una conexión de transmisión. También tenga en cuenta: si no agrega una longitud de contenido, la mayoría de los servidores HTTP lo configurarán Transfer-Encoding: chunked;
. Curiosamente, la fragmentación de HTTP advierte y causa confusión.
La confusión surge de una advertencia algo vaga en la sección de Notas de la descripción de W3 EventSource:
También se advierte a los autores que la fragmentación de HTTP puede tener efectos negativos inesperados sobre la confiabilidad de este protocolo. Siempre que sea posible, se debe deshabilitar la fragmentación para servir secuencias de eventos a menos que la velocidad de los mensajes sea lo suficientemente alta como para que esto no importe.
Lo que llevaría a creer que Transfer-Encoding: chunked;
es malo para SSE. Sin embargo: este no es necesariamente el caso, solo es un problema cuando su servidor web está haciendo el fragmento por usted (sin conocer la información sobre sus datos). Entonces, aunque la mayoría de las publicaciones sugerirán que agregar chunked_transfer_encoding off;
esto no es necesario en el caso típico [3].
Buffering (el verdadero problema)
De donde provienen la mayoría de los problemas es tener algún tipo de almacenamiento en búfer entre el servidor de aplicaciones y el cliente. Por defecto [4], Nginx usa
proxy_buffering on
(también eche un vistazo uwsgi_buffering
y fastcgi_buffering
dependiendo de su aplicación) y puede optar por almacenar los fragmentos que desea enviar a su cliente. Esto es algo malo porque la naturaleza en tiempo real de SSE se rompe.
Sin embargo, en lugar de recurrir proxy_buffering off
a todo, en realidad es mejor (si puede) agregar el X-Accel-Buffering: no
encabezado de respuesta en el código del servidor de su aplicación para desactivar solo el almacenamiento en búfer para la respuesta basada en SSE y no para todas las respuestas que provienen de su aplicación servidor. Bonificación: esto también funcionará para uwsgi
y fastcgi
.
Solución
Entonces, la configuración realmente importante son los encabezados de respuesta del servidor de aplicaciones:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
Y, potencialmente, la implementación de algún mecanismo de ping para que la conexión no permanezca inactiva durante demasiado tiempo. El peligro de esto es que Nginx cerrará las conexiones inactivas según lo establecido mediante la keepalive
configuración.
[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
X-Accel-Buffering: no
encabezado fue clave para mí, pero lo más importante es que tuve que hacer lo que @ c4urself escribió: "agregue X-Accel-Buffering: no como encabezado de respuesta en el código del servidor de su aplicación ". Agregar este encabezado a una sección de ubicación en mi configuración de nginx no funcionó: toda la secuencia del evento esperó ser enviada hasta después de que la aplicación finalizó / finalizó.proxy_http_version 1.1;
necesario? Estoy tratando de ejecutar más de 6 secuencias SSE desde un navegador y, por lo tanto, necesito HTTP2.