Côté serveur avec Sinatra avec un bloc stream
.
get '/stream', :provides => 'text/event-stream' do
stream :keep_open do |out|
connections << out
out.callback { connections.delete(out) }
end
end
Côté client:
var es = new EventSource('/stream');
es.onmessage = function(e) { $('#chat').append(e.data + "\n") };
Lorsque j'utilise l'application directement, via http://localhost:9292/
, tout fonctionne parfaitement. La connexion est persistante et tous les messages sont transmis à tous les clients.
Cependant, quand il passe par Nginx, http://chat.dev
, la connexion est interrompue et une reconnexion se déclenche toutes les secondes environ.
La configuration de Nginx me semble correcte:
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;
}
}
A tenté keepalive 1024
dans la section upstream
ainsi que proxy_set_header Connection keep-alive;
in location
.
Rien n'y fait :(
Aucune connexion persistante et aucun message transmis à aucun client.
Votre configuration Nginx est correcte, vous manquez juste quelques lignes.
Voici un "trio magique" faisant fonctionner EventSource
via Nginx:
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
Placez-les dans la section location
et cela devrait fonctionner.
Vous devrez peut-être également ajouter
proxy_buffering off;
proxy_cache off;
Ce n'est pas une façon officielle de procéder.
Je me suis retrouvé avec cela par "essais et erreurs" + "googler" :)
Une autre option consiste à inclure dans votre réponse un en-tête "X-Accel-Buffering" avec la valeur "non". Nginx le traite spécialement, voir http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
N'écrivez pas cela vous-même. Nginx est un merveilleux serveur événementiel et possède des modules qui gèreront SSE pour vous sans aucune dégradation des performances de votre serveur en amont.
Découvrez https://github.com/wandenberg/nginx-Push-stream-module
La façon dont cela fonctionne est que l'abonné (navigateur utilisant SSE) se connecte à Nginx, et la connexion s'arrête là. L'éditeur (votre serveur derrière Nginx) enverra un POST à Nginx à un itinéraire correspondant et à ce moment-là, Nginx transmettra immédiatement à l'écouteur EventSource en attente dans le navigateur.
Cette méthode est beaucoup plus évolutive que d'avoir votre serveur Web Ruby gérer ces "longues interrogations" SSE connexions).