Тривале з'єднання
Події, надіслані сервером (SSE) - це тривале HTTP-з'єднання **, тому для початку нам потрібно це:
proxy_http_version 1.1;
proxy_set_header Connection "";
ПРИМІТКА: TCP-з'єднання в HTTP / 1.1 зберігаються за замовчуванням, тому встановлення заголовка З'єднання порожнім - це правильно і є пропозицією Nginx.
Збиток передачі-кодування
Тепер убік; Відповіді SSE не встановлюють заголовок довжини вмісту, оскільки вони не можуть знати, скільки даних буде надіслано, натомість їм потрібно використовувати заголовок Transfer-Encoding [0] [1], що дозволяє здійснювати потокове з'єднання. Також зверніть увагу: якщо ви не додасте Довжина контенту, більшість серверів HTTP встановлять Transfer-Encoding: chunked;
для вас. Як не дивно, HTTP чанчінг застерігає від і викликає плутанину.
Плутанина випливає з дещо невиразним попередженням у розділі Примітки опису W3 EventSource:
Автори також попередили, що відмітка HTTP може мати несподівані негативні наслідки на надійність цього протоколу. Там, де це можливо, слід відключити розміщення для подачі потоків подій, якщо частота повідомлень не є достатньо високою, щоб це не мало значення.
Що призведе до того, що можна повірити, що Transfer-Encoding: chunked;
це SSE - це погана річ. Однак це не обов'язково так, це лише проблема, коли ваш веб-сервер робить замість вас (не знаючи інформації про ваші дані). Отже, хоча більшість дописів пропонують додавати chunked_transfer_encoding off;
це не потрібно в типовому випадку [3].
Буферизація (справжня проблема)
Там, де виникає більшість проблем, є будь-який тип буферизації між сервером додатків і клієнтом. За замовчуванням [4], Nginx використовує
proxy_buffering on
(також огляньте uwsgi_buffering
та fastcgi_buffering
залежно від вашої програми) і може вибрати буфер шматки, які ви хочете вийти на ваш клієнт. Це погано, тому що в режимі реального часу SSE порушується.
Однак замість того, щоб повертатись proxy_buffering off
до всього, насправді найкраще (якщо ви можете) додати X-Accel-Buffering: no
як код заголовка відповіді у код сервера додатків, щоб вимкнути буферизацію лише для відповіді на основі SSE, а не для всіх відповідей, які надходять із вашої програми сервер. Бонус: це також буде працювати uwsgi
і для fastcgi
.
Рішення
І тому дійсно важливими налаштуваннями є наслідок заголовки відповідей програми та сервера:
Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;
І, можливо, реалізація якогось механізму ping, щоб з'єднання не залишалося в режимі очікування занадто довго. Небезпека цього полягає в тому, що Nginx закриє непрацюючі з'єднання, як встановлено, використовуючи keepalive
налаштування.
[0] https://tools.ietf.org/html/rfc2616#section-3.6
[1] https://en.wikipedia.org/wiki/Chunked_transfer_encoding
[2] https://www.w3.org/TR / 2009 / WD-eventsource-20091029 / # text-event-stream
[3] https://github.com/whatwg/html/isissue/515
[4] http://nginx.org/en/docs/http/ ngx_http_proxy_module.html # proxy_buffering
[5] https://tools.ietf.org/html/rfc7230#section-6.3
[6] https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88