我已经阅读了很多关于 Nginx 配置适合 SSE 的不同问题,并就使用哪些设置得出了一些令人困惑的结果:
- https://stackoverflow.com/questions/17529421/sending-server-sent-events-through-a-socket-in-c
- https://stackoverflow.com/questions/13672743/eventsource-server-sent-events-through-nginx
- https://stackoverflow.com/questions/21630509/server-sent-events-connection-timeout-on-node-js-via-nginx
那么正确答案是什么?
长时间运行的连接
服务器发送事件 (SSE) 是一个长时间运行的 HTTP 连接**,所以对于初学者来说,我们需要这个:
分块传输编码
现在顺便说一句;SSE 响应不设置 Content-Length 标头,因为它们不知道将发送多少数据,而是需要使用 Transfer-Encoding 标头[0][1],这允许流连接。另请注意:如果您不添加 Content-Length,大多数 HTTP 服务器将为
Transfer-Encoding: chunked;
您设置。奇怪的是,HTTP 分块警告并导致混乱。混淆源于 W3 EventSource 描述的注释部分中的一个有点模糊的警告:
这会让人们相信
Transfer-Encoding: chunked;
对 SSE 来说是一件坏事。但是:情况不一定如此,只有当您的网络服务器为您进行分块(不知道有关您的数据的信息)时,这才是问题。因此,虽然大多数帖子都会建议chunked_transfer_encoding off;
在典型情况下添加此功能 [3]。缓冲(真正的问题)
大多数问题的根源在于应用服务器和客户端之间存在任何类型的缓冲。默认情况下[4],Nginx 使用
proxy_buffering on
(也可以查看uwsgi_buffering
并fastcgi_buffering
取决于您的应用程序)并且可以选择缓冲您想要发送给客户端的块。这是一件坏事,因为 SSE 的实时性中断了。但是,
proxy_buffering off
实际上最好(如果可以的话)X-Accel-Buffering: no
在您的应用程序服务器代码中添加作为响应标头,以仅关闭基于 SSE 的响应的缓冲,而不是针对来自您的应用程序的所有响应,而不是转向所有内容服务器。奖励:这也适用于uwsgi
andfastcgi
。解决方案
所以真正重要的设置实际上是应用服务器响应头:
并且可能会实施一些 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