通过Nginx发送EventSource/Server-Sent事件

Luk*_*yer 66 ruby nginx sinatra

在服务器端使用带有stream块的Sinatra .

get '/stream', :provides => 'text/event-stream' do
  stream :keep_open do |out|
    connections << out
    out.callback { connections.delete(out) }
  end
end
Run Code Online (Sandbox Code Playgroud)

在客户端:

var es = new EventSource('/stream');
es.onmessage = function(e) { $('#chat').append(e.data + "\n") };
Run Code Online (Sandbox Code Playgroud)

当我直接使用应用程序,通过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;
  }
}
Run Code Online (Sandbox Code Playgroud)

尝试keepalive 1024upstream部分以及proxy_set_header Connection keep-alive;location.

什么都没有帮助:(

没有持久连接和消息未传递给任何客户端.

小智 151

你的Nginx配置是正确的,你只是错过了几行.

这是一个EventSource通过Nginx工作的"魔术三重奏" :

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
Run Code Online (Sandbox Code Playgroud)

将它们放入location部分,它应该工作.

您可能还需要添加

proxy_buffering off;
proxy_cache off;
Run Code Online (Sandbox Code Playgroud)

这不是官方的做法.

我最后通过"试验和错误"+"谷歌搜索":)

  • 这对我不起作用,直到我还添加了以下内容: - proxy_buffering off; proxy_cache off; (11认同)
  • 我只需在响应标头中添加“X-Accel-Buffering:no”即可使其工作 (4认同)
  • 效果很好。伙计,这很难调试。非常感谢! (2认同)
  • 服务器响应"X-Accel-Buffering:no"标头有很大帮助!(见:http://wiki.nginx.org/X-accel#X-Accel-Buffering) (2认同)
  • 您的试错+我的第一次google点击=我喜欢堆栈溢出.谢谢! (2认同)
  • 你刚刚按照官方方式做了,干得好!http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive (2认同)

小智 9

另一种选择是在您的响应中包含值为"no"的"X-Accel-Buffering"标头.Nginx特别对待它,请参阅http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering

  • 谢谢,这帮助我解决了问题,而无需更改 nginx 配置 (2认同)

Mar*_*cny 7

不要自己从头开始写这个.Nginx是一个很棒的服务器,它有一些模块可以为你处理SSE而不会降低上游服务器的性能.

查看https://github.com/wandenberg/nginx-push-stream-module

它的工作方式是订户(使用SSE的浏览器)连接到Nginx,连接在那里停止.发布者(你的Nginx背后的服务器)会在相应的路由上向Nginx发送一个POST,在那一刻,Nginx将立即转发到浏览器中等待的EventSource监听器.

这种方法比ruby webserver处理这些"长轮询"SSE连接更具可扩展性.


Mar*_*sel 5

您好,将此评论从Did提升为答案:这是我在通过 Nginx 使用 HttpStreamingResponse 从 Django 进行流式传输时需要添加的唯一内容。上面的所有其他开关都没有帮助,但这个标头有帮助。

\n

让服务器响应“X-Accel-Buffering: no”标头会很有帮助!(参见:wiki.nginx.org/X-accel#X-Accel-Buffering)\xe2\x80\x93\n2013 年 7 月 1 日 16:24

\n