EventSource/Server-通过 Nginx 发送事件

在服务器端使用带有 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区试了 keepalive 1024,在 location区试了 proxy_set_header Connection keep-alive;

没有任何帮助:

没有未传递到任何客户端的持久连接和消息。

45860 次浏览

Your Nginx config is correct, you just miss few lines.

Here is a "magic trio" making EventSource working through Nginx:

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;

Place them into location section and it should work.

You may also need to add

proxy_buffering off;
proxy_cache off;

That's not an official way of doing it.

I ended up with this by "trial and errors" + "googling" :)

Don't write this from scratch yourself. Nginx is a wonderful evented server and has modules that will handle SSE for you without any performance degradation of your upstream server.

Check out https://github.com/wandenberg/nginx-push-stream-module

The way it works is the subscriber (browser using SSE) connects to Nginx, and the connection stops there. The publisher (your server behind Nginx) will send a POST to Nginx at a corresponding route and in that moment Nginx will immediately forward to the waiting EventSource listener in the browser.

This method is much more scalable than having your ruby webserver handle these "long-polling" SSE connections.

Another option is to include in your response a 'X-Accel-Buffering' header with value 'no'. Nginx treats it specially, see http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering