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: les connexions 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é; Les réponses 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 une connexion en streaming. Notez également: si vous n'ajoutez pas de longueur de contenu, la plupart des serveurs HTTP seront définis 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 servir les 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 que Transfer-Encoding: chunked;
c'est une mauvaise chose pour l'ESS. 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
(regardez également uwsgi_buffering
et en fastcgi_buffering
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 est interrompue.
Cependant, au lieu de tourner proxy_buffering off
pour tout, il est préférable (si vous le pouvez) d'ajouter l' X-Accel-Buffering: no
en-tête de réponse dans votre code de 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 application. serveur. 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 comme défini en utilisant le keepalive
paramètre.
[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.3
[6] https://gist.github.com/CMCDragonkai/6bfade6431e9ffb7fe88
X-Accel-Buffering: no
tête était essentiel pour moi, mais surtout, je devais faire comme @ c4urself a écrit: "ajoutez le X-Accel-Buffering: no comme en-tête de réponse dans votre code de serveur d'application ". L'ajout de cet en-tête à une section d'emplacement dans ma configuration nginx n'a pas fonctionné - l'ensemble du flux d'événements a attendu d'être envoyé jusqu'à la fin / la fin de l'application.proxy_http_version 1.1;
nécessaire? J'essaie d'exécuter plus de 6 flux SSE à partir d'un navigateur et j'ai donc besoin de HTTP2.