Для серверних подій (SSE) яка конфігурація проксі-сервера Nginx підходить?


21

Я прочитав купу різних запитань щодо того, яка конфігурація Nginx підходить для SSE, і прийшов із заплутаними результатами щодо налаштувань, які слід використовувати:

То яка правильна відповідь?

Відповіді:


46

Тривале з'єднання

Події, надіслані сервером (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


Чи можете ви детальніше розглянути, що таке механізм пінг? Це просто натискання порожнього повідомлення на канал? Я встановив заголовки рівня nginx та додатків, але я все ще отримую 504 тайм-аут від nginx для будь-якої кінцевої точки джерела події.
wgwz

ping - це просто деякі (фальшиві) дані, що надсилаються з інтервалом через з'єднання, на клієнті ви можете обробляти цей ping і ігнорувати його. ПРИМІТКА: якщо ваше з’єднання взагалі не працює, пінгінг не допоможе, щось інше не так.
c4urself

2
Я додав заголовки відповідей, як було запропоновано, і це працює. Я не вносив жодних змін у конфігурацію nginx v1.12, і поки що жодних проблем.
Міккель

1
Додавання X-Accel-Buffering: noзаголовка було для мене ключовим, але що важливо, я повинен був зробити так, як @ c4urself написав: "додати X-Accel-Buffering: ні як заголовок відповіді у код вашого сервера додатків ". Додавання цього заголовка до розділу місцеположення в моєму конфігурації nginx не спрацювало - весь потік події чекав на надсилання до завершення / припинення програми.
MDMower

Чи proxy_http_version 1.1; потрібно? Я намагаюся запустити більше 6 потоків SSE з браузера, і тому мені потрібен HTTP2.
Білал Фазлані
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.