EventSource / 服务器通过 Nginx 发送的事件
Posted
技术标签:
【中文标题】EventSource / 服务器通过 Nginx 发送的事件【英文标题】:EventSource / Server-Sent Events through Nginx 【发布时间】:2012-11-20 07:09:57 【问题描述】:在服务器端使用带有 stream
块的 Sinatra。
get '/stream', :provides => 'text/event-stream' do
stream :keep_open do |out|
connections << out
out.callback connections.delete(out)
end
end
在客户端:
var es = new EventSource('/stream');
es.onmessage = function(e) $('#chat').append(e.data + "\n") ;
当我通过http://localhost:9292/
直接使用应用程序时,一切正常。连接是持久的,所有消息都会传递给所有客户端。
但是,当它通过 nginx http://chat.dev
时,连接会断开,并且每隔一秒左右就会触发一次重新连接。
我觉得 Nginx 设置没问题:
upstream chat_dev_upstream
server 127.0.0.1:9292;
server
listen 80;
server_name chat.dev;
location /
proxy_pass http://chat_dev_upstream;
proxy_buffering off;
proxy_cache off;
proxy_set_header Host $host;
在upstream
部分以及proxy_set_header Connection keep-alive;
in location
中尝试了keepalive 1024
。
没有任何帮助:(
没有持久连接和未传递给任何客户端的消息。
【问题讨论】:
【参考方案1】:你的 Nginx 配置是正确的,你只是漏掉了几行。
这是一个通过 Nginx 制作 EventSource
的“魔法三重奏”:
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
将它们放入location
部分,它应该可以工作。
您可能还需要添加
proxy_buffering off;
proxy_cache off;
这不是官方的做法。
我通过“反复试验”+“谷歌搜索”得到了这个结果:)
【讨论】:
效果很好。伙计,这很难调试。非常感谢! 让服务器响应“X-Accel-Buffering: no”标头有很大帮助! (见:wiki.nginx.org/X-accel#X-Accel-Buffering) 这对我不起作用,直到我还添加了以下内容:- proxy_buffering off; proxy_cache 关闭; 你的反复试验+我的第一个谷歌点击=我喜欢堆栈溢出。谢谢! 你刚刚做了官方的方式,干得好! nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive【参考方案2】:另一种选择是在您的响应中包含一个值为“no”的“X-Accel-Buffering”标头。 Nginx 对其特殊对待, 见http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
【讨论】:
谢谢,这帮助我在不更改 nginx 配置的情况下解决了问题【参考方案3】:不要自己从头开始编写。 Nginx 是一个很棒的事件服务器,它的模块可以为您处理 SSE,而不会降低上游服务器的性能。
查看https://github.com/wandenberg/nginx-push-stream-module
它的工作方式是订阅者(使用 SSE 的浏览器)连接到 Nginx,然后连接停止。发布者(Nginx 后面的服务器)将在相应的路由上向 Nginx 发送 POST,此时 Nginx 将立即转发到浏览器中等待的 EventSource 侦听器。
这种方法比让您的 ruby 网络服务器处理这些“长轮询”SSE 连接更具可扩展性。
【讨论】:
如何使这个高度可用?就像部署 2 个 nginx 实例,当您向其中一个实例发布消息时,它会发布给订阅了这两个实例的客户端?以上是关于EventSource / 服务器通过 Nginx 发送的事件的主要内容,如果未能解决你的问题,请参考以下文章
服务器发送事件; `EventSource.onmessage`没有触发
通过SSE(Server-Send Event)实现服务器主动向浏览器端推送消息
通过 CDK 中的 ARN 将 eventSource 添加到 Lambda
从(服务器发送的)EventSource 创建一个 RxJS Observable