对于服务器发送事件 (SSE),什么 Nginx 代理配置是合适的?

c4u*_*elf 32 nginx

我已经阅读了很多关于什么 Nginx 配置适合 SSE 的不同问题,并提出了一些关于使用哪些设置的令人困惑的结果:

那么正确答案是什么?

c4u*_*elf 66

长时间运行的连接

服务器发送事件 (SSE) 是一个长时间运行的 HTTP 连接**,所以对于初学者来说,我们需要这个:

proxy_http_version 1.1;
proxy_set_header Connection "";
Run Code Online (Sandbox Code Playgroud)

注意: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;
Run Code Online (Sandbox Code Playgroud)

并且可能会实施一些 ping 机制,以便连接不会闲置太久。这样做的危险是 Nginx 将使用keepalive设置关闭空闲连接。


[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

  • 我按照建议添加了响应标头并且它有效。我没有对 nginx v1.12 配置进行任何更改,到目前为止没有任何问题。 (3认同)
  • 添加`X-Accel-Buffering: no` 标头对我来说很关键,但重要的是,我必须按照@c4urself 写道:“添加 X-Accel-Buffering: no 作为响应标头*在您的应用程序服务器代码中* ”。将此标头添加到我的 nginx 配置中的位置部分不起作用 - 整个事件流等待发送,直到应用程序完成/终止之后。 (3认同)