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


Answers:


45

长期运行的连接

服务器发送事件(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;对上证所不利。但是:不一定是这种情况,这只是当您的Web服务器为您做分块(不知道有关您的数据的信息)时的问题。因此,尽管大多数帖子会建议chunked_transfer_encoding off;在典型情况下无需添加此功能[3]。

缓冲(真正的问题)

大多数问题出在哪里,就是应用服务器与客户端之间存在任何类型的缓冲。默认情况下[4],Nginx使用 proxy_buffering on(也要看一下uwsgi_bufferingfastcgi_buffering取决于您的应用程序),并且可以选择缓冲要发送给客户端的块。这是一件坏事,因为SSE的实时性会中断。

但是,proxy_buffering off最好不要(如果可以)将s X-Accel-Buffering: no作为响应标头添加到应用程序服务器代码中,以便仅对基于SSE的响应而不是对来自应用程序的所有响应都关闭缓冲服务器。奖励:这对于uwsgi和也适用fastcgi

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

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

并可能执行某种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/zh/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


您能详细说明一下ping机制是什么吗?它是否只是向该频道推送空消息?我已经设置了nginx和应用程序级别标题,但是对于任何事件源端点,我仍然从nginx收到504超时。
wgwz

ping只是通过连接间隔发送的一些(虚假)数据,在客户端上,您可以处理此ping并忽略它。注意:如果您的连接根本无法正常工作,则ping操作无济于事,这是其他问题。
c4urself

2
我按照建议添加了响应头,并且可以正常工作。我没有对nginx v1.12配置进行任何更改,到目前为止没有任何问题。
Mikkel'7

1
添加X-Accel-Buffering: no标头对我来说很关键,但重要的是,我必须按照@ c4urself的描述进行操作:“添加X-Accel-Buffering:否作为您的应用程序服务器代码中的响应标头”。将此标头添加到我的nginx配置中的location部分不起作用-整个事件流一直等待发送,直到应用程序完成/终止。
MDMower

proxy_http_version 1.1; 必要吗?我试图从浏览器运行6个以上的SSE流,因此我需要HTTP2。
Bilal Fazlani
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.