События EventSource/Server-Sent через Nginx
На стороне сервера с использованием Sinatra с блоком stream
.
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;
}
}
Пробовал keepalive 1024
в разделе upstream
, а также proxy_set_header Connection keep-alive;
в location
.
Ничего не помогает: (
Нет постоянных соединений и сообщений, которые не передаются никаким клиентам.
Ответы
Ответ 1
Ваша конфигурация Nginx верна, вы просто пропускаете несколько строк.
Вот "волшебное трио", создающее EventSource
, работающее через Nginx:
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
Поместите их в раздел location
, и он должен работать.
Вам также может потребоваться добавить
proxy_buffering off;
proxy_cache off;
Это не официальный способ сделать это.
Я закончил это с помощью "проб и ошибок" + "googling":)
Ответ 2
Другой вариант - включить в свой ответ заголовок "X-Accel-Buffering" со значением "нет". Nginx рассматривает его специально,
см. http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
Ответ 3
Не пишите это с нуля самостоятельно. Nginx - замечательный сервер с событиями и имеет модули, которые будут обрабатывать SSE для вас без снижения производительности вашего восходящего сервера.
Отъезд https://github.com/wandenberg/nginx-push-stream-module
Как это работает, абонент (браузер с использованием SSE) подключается к Nginx, и соединение останавливается там. Издатель (ваш сервер за Nginx) отправит POST на Nginx по соответствующему маршруту, и в этот момент Nginx немедленно перейдет в ожидающий прослушиватель EventSource в браузере.
Этот метод гораздо более масштабируемый, чем ваш рубиновый веб-сервер, обрабатывающий эти "длинные опросы" SSE-соединений.