web-dev-qa-db-fra.com

Pour les événements envoyés par le serveur (SSE), quelle configuration de proxy Nginx est appropriée?

J'ai lu un tas de questions différentes sur la configuration Nginx appropriée pour SSE et j'ai trouvé des résultats déroutants concernant les paramètres à utiliser:

Alors, quelle est la bonne réponse?

23
c4urself

Connexion longue durée

Les événements envoyés par le serveur (SSE) sont une connexion HTTP de longue durée **, donc pour les débutants, nous avons besoin de ceci:

proxy_http_version 1.1;
proxy_set_header Connection "";

REMARQUE: TCP dans HTTP/1.1 sont persistantes par défaut, donc définir l'en-tête Connection sur vide fait la bonne chose et est la suggestion de Nginx.

Codage de transfert en morceaux

Maintenant un aparté; SSE ne définissent pas d'en-tête Content-Length car elles ne peuvent pas savoir combien de données seront envoyées, mais doivent utiliser l'en-tête Transfer-Encoding [0] [1], ce qui permet Remarque: si vous n'ajoutez pas de longueur de contenu, la plupart des serveurs HTTP définiront Transfer-Encoding: chunked; pour vous. Étrangement, HTTP chunking a mis en garde et cause de la confusion.

La confusion provient d'un avertissement quelque peu vague dans la section Notes de la description de W3 EventSource:

Les auteurs sont également avertis que le découpage HTTP peut avoir des effets négatifs inattendus sur la fiabilité de ce protocole. Dans la mesure du possible, la segmentation doit être désactivée pour la diffusion de flux d'événements, sauf si le taux de messages est suffisamment élevé pour que cela n'ait pas d'importance.

Ce qui ferait croire Transfer-Encoding: chunked; est une mauvaise chose pour SSE. Cependant: ce n'est pas nécessairement le cas, c'est seulement un problème lorsque votre serveur Web effectue le segmentage pour vous (sans connaître les informations sur vos données). Ainsi, alors que la plupart des articles suggèrent d'ajouter chunked_transfer_encoding off; ce n'est pas nécessaire dans le cas typique [3].

Mise en mémoire tampon (le vrai problème)

La plupart des problèmes proviennent de la mise en mémoire tampon de tout type entre le serveur d'applications et le client. Par défaut [4], Nginx utilise proxy_buffering on (jetez également un œil à uwsgi_buffering et fastcgi_buffering en fonction de votre application) et peut choisir de mettre en mémoire tampon les morceaux que vous souhaitez envoyer à votre client. C'est une mauvaise chose car la nature en temps réel de SSE casse.

Cependant, au lieu de tourner proxy_buffering off pour tout, il est préférable (si vous le pouvez) d'ajouter le X-Accel-Buffering: no comme en-tête de réponse dans le code de votre serveur d'applications pour désactiver uniquement la mise en mémoire tampon pour la réponse basée sur SSE et non pour toutes les réponses provenant de votre serveur d'applications. Bonus: cela fonctionnera également pour uwsgi et fastcgi.

Solution

Et donc les paramètres vraiment importants sont en fait les en-têtes de réponse du serveur d'applications:

Content-Type: text/event-stream;
Cache-Control: no-cache;
X-Accel-Buffering: no;

Et potentiellement l'implémentation d'un mécanisme de ping afin que la connexion ne reste pas inactive trop longtemps. Le danger est que Nginx ferme les connexions inactives définies en utilisant le paramètre 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/issues/515
[4] http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering
[5] https://tools.ietf.org/html/rfc7230#section-6.
[6] https://Gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88

49
c4urself