web-dev-qa-db-fra.com

Événements EventSource / Server-Sent via Nginx

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.

63
Lukas Mayer

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" :)

143
user904990

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

6
E1.

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).

5
Martin Konecny