对于服务器发送事件(SSE),哪种 Nginx 代理配置合适?

对于服务器发送事件(SSE),哪种 Nginx 代理配置合适?

答案1

长时间运行的连接

服务器发送事件 (SSE) 是一种长期运行的 HTTP 连接**,因此首先我们需要以下内容:

proxy_http_version 1.1;
proxy_set_header Connection "";

注意:HTTP/1.1 中的 TCP 连接默认是持久的,因此将 Connection 标头设置为空是正确的,也是 Nginx 的建议。

分块传输编码

现在顺便说一句;SSE 响应不会设置 Content-Length 标头,因为它们不知道将发送多少数据,而是需要使用 Transfer-Encoding 标头[0][1],这允许流式连接。还请注意:如果您不添加 Content-Length,大多数 HTTP 服务器都会Transfer-Encoding: chunked;为您设置。奇怪的是,HTTP 分块会发出警告并引起混乱。

这种混淆源于 W3 EventSource 描述的注释部分中的一个模糊的警告:

作者还需注意,HTTP 分块可能会对该协议的可靠性产生意想不到的负面影响。在可能的情况下,应禁用分块来处理事件流,除非消息速率足够高,因此不会产生影响。

这会让人觉得Transfer-Encoding: chunked;这对 SSE 来说是一件坏事。然而:情况不一定如此,只有当您的网络服务器为您进行分块(不知道您的数据信息)时,这才会成为问题。因此,虽然大多数帖子会建议添加chunked_transfer_encoding off;此功能,但在典型情况下没有必要[3]。

缓冲(真正的问题)

大多数问题都源于应用服务器和客户端之间的缓冲类型。默认情况下[4],Nginx 使用 proxy_buffering on(也请查看uwsgi_bufferingfastcgi_buffering取决于您的应用程序)并可能选择缓冲您想要发送到客户端的块。这是一件坏事,因为 SSE 的实时性被破坏了。

但是,proxy_buffering off实际上,最好(如果可以的话)X-Accel-Buffering: no在应用服务器代码中添加作为响应标头,以便只关闭基于 SSE 的响应的缓冲,而不是关闭来自应用服务器的所有响应的缓冲,而不是关闭所有响应的缓冲。额外好处:这也适用于uwsgifastcgi

解决方案

因此真正重要的设置实际上是应用服务器响应标头:

Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;

并且可能实现某种 ping 机制,以便连接不会闲置太久。这样做的危险在于 Nginx 将按照设置关闭空闲连接keepalive


[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

相关内容