EventSource / Server-Sent Events über Nginx

78

Auf der Serverseite mit Sinatra mit einem streamBlock.

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

Auf Kundenseite:

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

Wenn ich die App direkt über benutze http://localhost:9292/, funktioniert alles perfekt. Die Verbindung ist dauerhaft und alle Nachrichten werden an alle Clients weitergeleitet.

Wenn es jedoch über Nginx geht, http://chat.devwird die Verbindung getrennt und jede Sekunde wird eine erneute Verbindung ausgelöst.

Das Nginx-Setup sieht für mich in Ordnung aus:

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;
  }
}

Versucht keepalive 1024in upstreamAbschnitt sowie proxy_set_header Connection keep-alive;in location.

Nichts hilft :(

Keine dauerhaften Verbindungen und Nachrichten, die nicht an Clients weitergegeben wurden.

Lukas Mayer
quelle

Antworten:

191

Ihre Nginx-Konfiguration ist korrekt, Sie verpassen nur wenige Zeilen.

Hier ist ein "magisches Trio", EventSourcedas Nginx durcharbeitet:

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;

Platzieren Sie sie in locationAbschnitt und es sollte funktionieren.

Möglicherweise müssen Sie auch hinzufügen

proxy_buffering off;
proxy_cache off;

Das ist keine offizielle Vorgehensweise.

Ich endete damit durch "Versuch und Irrtum" + "googeln" :)

Inaimathi
quelle
2
Funktioniert so gut. Mann, das war schwer zu debuggen. Vielen Dank!
Chris Case
2
Es hilft viel, wenn der Server mit einem "X-Accel-Buffering: no" -Header antwortet! (siehe: wiki.nginx.org/X-accel#X-Accel-Buffering )
Hat
15
Das hat bei mir nicht funktioniert, bis ich auch Folgendes hinzugefügt habe: - proxy_buffering off; proxy_cache aus;
Malcolm Sparks
4
Dein Versuch und Irrtum + mein erster Google-Treffer = Ich liebe Stapelüberlauf. Vielen Dank!
Chris Ray
2
Du hast gerade den OFFIZIELLEN WEG gemacht, tolle Arbeit! nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive
Weihang Jian
14

Eine andere Möglichkeit besteht darin, in Ihre Antwort einen 'X-Accel-Buffering'-Header mit dem Wert' no 'aufzunehmen. Nginx behandelt es speziell, siehe http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering

E1.
quelle
Vielen Dank, dies hat mir geholfen, das Problem zu lösen, ohne die Nginx-Konfiguration zu ändern
Thanh Trung
9

Schreiben Sie das nicht selbst von Grund auf neu. Nginx ist ein wunderbarer Event-Server und verfügt über Module, die SSE für Sie verarbeiten, ohne dass die Leistung Ihres Upstream-Servers beeinträchtigt wird.

Überprüfen Sie https://github.com/wandenberg/nginx-push-stream-module

Die Art und Weise, wie es funktioniert, ist, dass der Teilnehmer (Browser, der SSE verwendet) eine Verbindung zu Nginx herstellt und die Verbindung dort stoppt. Der Herausgeber (Ihr Server hinter Nginx) sendet einen POST an Nginx auf einer entsprechenden Route und in diesem Moment leitet Nginx sofort an den wartenden EventSource-Listener im Browser weiter.

Diese Methode ist viel skalierbarer, als wenn Ihr Ruby-Webserver diese SSE-Verbindungen mit langen Abfragen verarbeitet.

Martin Konecny
quelle