Raison possible des codes d'erreur NGINX 499

116

Je reçois beaucoup de 499 codes d'erreur NGINX. Je vois que c'est un problème côté client. Ce n'est pas un problème avec NGINX ou ma pile uWSGI. Je note la corrélation dans les journaux uWSGI quand un 499.

address space usage: 383692800 bytes/365MB} {rss usage: 167038976
bytes/159MB} [pid: 16614|app: 0|req: 74184/222373] 74.125.191.16 ()
{36 vars in 481 bytes} [Fri Oct 19 10:07:07 2012] POST /bidder/ =>
generated 0 bytes in 8 msecs (HTTP/1.1 200) 1 headers in 59 bytes (1
switches on core 1760)
SIGPIPE: writing to a closed pipe/socket/fd (probably the client
disconnected) on request /bidder/ (ip 74.125.xxx.xxx) !!!
Fri Oct 19 10:07:07 2012 - write(): Broken pipe [proto/uwsgi.c line
143] during POST /bidder/ (74.125.xxx.xxx)
IOError: write error

Je cherche une explication plus approfondie et j'espère que ce n'est pas un problème avec ma configuration NGINX pour uwsgi. Je le prends pour argent comptant. Cela semble être un problème client.

Tampa
la source
Avez-vous déjà trouvé une solution à cela? Je vois exactement le même problème avec uWSGI et nginx.
Raj
1
Je l'obtiens lorsque j'annule une requête jQuery ajax.
mpen
1
Je sais que c'est une question très ancienne, mais le nombre de questions mal placées sur le SO est stupéfiant. Cela appartient clairement à SF.
Sosukodo

Réponses:

164

HTTP 499 dans Nginx signifie que le client a fermé la connexion avant que le serveur ne réponde à la demande. Dans mon expérience, est généralement causé par le délai d'attente côté client . Comme je le sais, c'est un code d'erreur spécifique à Nginx.

mrbo
la source
1
En tant que cas particulier, j'ai remarqué que cela se produisait parfois lorsque l'utilisateur final double-cliquait sur un bouton d'envoi de formulaire. Le formulaire est envoyé deux fois, mais une seule réponse est attendue par le client. Cela peut être contourné en désactivant (au moins pendant quelques secondes) les boutons dans JS la première fois qu'ils sont cliqués.
Antoine Pinsard
14
Il est important de noter que le «client» peut en fait être un proxy. Par exemple, si vous utilisez un équilibreur de charge, cela peut annuler la demande au serveur nginx en raison d'un délai d'expiration.
Brad Koch
Cela se produit sur mon APP angulaire si l'utilisateur ferme l'onglet et que mes demandes d'API ne sont pas terminées.
Vivek Saurabh le
Il est important de noter que cela peut également être causé par le serveur ; si le serveur met trop de temps à répondre, le client abandonne.
ijoseph le
78

Dans mon cas, j'étais impatient et j'ai fini par mal interpréter le journal.

En fait, le vrai problème était la communication entre nginx et uwsgi, et non entre le navigateur et nginx. Si j'avais chargé le site dans mon navigateur et que j'avais attendu assez longtemps, j'aurais obtenu un "504 - Bad Gateway". Mais cela a pris tellement de temps que j'ai continué à essayer des trucs, puis à actualiser le navigateur. Je n'ai donc jamais attendu assez longtemps pour voir l'erreur 504. Lors de l'actualisation dans le navigateur, c'est lorsque la demande précédente est fermée et Nginx écrit cela dans le journal comme 499.

Élaboration

Ici, je suppose que le lecteur en sait aussi peu que moi lorsque j'ai commencé à jouer.

Ma configuration était un proxy inverse, le serveur nginx et un serveur d'applications, le serveur uWSGI derrière. Toutes les demandes du client iraient au serveur nginx, puis transférées au serveur uWSGI, puis la réponse était renvoyée de la même manière. Je pense que c'est ainsi que tout le monde utilise nginx / uwsgi et est censé l'utiliser.

Mon nginx a fonctionné comme il se doit, mais quelque chose n'allait pas avec le serveur uwsgi. Il y a deux façons (peut-être plus) dans lesquelles le serveur uwsgi peut ne pas répondre au serveur nginx.

1) uWSGI dit: "Je suis en train de traiter, attendez et vous obtiendrez bientôt une réponse". nginx a une certaine période de temps, qu'il est prêt à attendre, fx 20 secondes. Après cela, il répondra au client, avec une erreur 504.

2) uWSGI est mort, ou uWSGi meurt pendant que nginx l'attend. nginx voit cela tout de suite et dans ce cas, il renvoie une erreur 499.

Je testais ma configuration en effectuant des requêtes dans le client (navigateur). Dans le navigateur, rien ne s'est passé, il s'est arrêté. Après peut-être 10 secondes (moins que le délai), j'ai conclu que quelque chose n'allait pas (ce qui était vrai) et j'ai fermé le serveur uWSGI à partir de la ligne de commande. Ensuite, j'irais dans les paramètres uWSGI, essayerais quelque chose de nouveau, puis redémarrerais le serveur uWSGI. Au moment où j'ai fermé le serveur uWSGI, le serveur nginx renverrait une erreur 499.

J'ai donc continué à déboguer avec l'erroe 499, ce qui signifie rechercher l'erreur 499 sur Google. Mais si j'avais attendu assez longtemps, j'aurais eu l'erreur 504. Si j'avais eu l'erreur 504, j'aurais pu mieux comprendre le problème et ensuite être en mesure de déboguer.

Donc, la conclusion est que le problème était avec uWGSI, qui n'arrêtait pas de s'accrocher ("Attendez encore un peu, juste un peu plus longtemps, alors j'aurai une réponse pour vous ...").

Comment j'ai résolu ce problème, je ne me souviens pas. Je suppose que cela pourrait être causé par beaucoup de choses.

Mads Skjern
la source
1
Comment avez-vous fini par résoudre ce problème? J'ai le même problème et je n'ai pas été en mesure de cerner la cause.
Colin Nichols
1
J'ai ajouté une élaboration, malheureusement, je ne pense pas que cela résoudra votre problème.
Mads Skjern le
1
Je voulais juste vous dire merci! J'ai eu exactement la même situation et cela m'a mis sur la bonne voie.
Aaron
3
@Shafiul: Mon élaboration n'explique pas ce qui a causé le problème avec uWSGI, il explique simplement que uWSGI en était la cause (et non nginx). L'élaboration décrit les symptômes et comment je les ai mal interprétés. Je comprends votre déception, mais vous avez mal compris l'essence de ma réponse. Cordialement.
Mads Skjern
2
Réponse extrêmement utile, ne supprimez jamais! Ces concepts devraient être étoffés quelque part dans la documentation, vous rendez un excellent service en expliquant comment il se comporte différemment de ce que la documentation impliquerait!
jerclarke
21

Le client a fermé la connexion ne signifie pas qu'il s'agit d'un problème de navigateur !? Pas du tout!

Vous pouvez trouver 499 erreurs dans un fichier journal si vous avez un LB (load balancer) devant votre serveur Web (nginx) soit AWS ou haproxy (personnalisé). Cela dit, le LB agira en tant que client de nginx.

Si vous exécutez les valeurs par défaut haproxy pour:

    timeout client  60000
    timeout server  60000

Cela signifierait que LB expirera après 60000 ms s'il n'y a pas de réponse de nginx. Des délais peuvent se produire pour les sites Web ou les scripts occupés qui nécessitent plus de temps pour l'exécution. Vous devrez trouver un délai d'expiration qui fonctionnera pour vous. Par exemple, étendez-le à:

    timeout client  180s
    timeout server  180s

Et vous serez probablement prêt.

En fonction de votre configuration, vous pouvez voir une erreur d'expiration de la passerelle 504 dans votre navigateur, ce qui indique que quelque chose ne va pas avec php-fpm, mais ce ne sera pas le cas avec 499 erreurs dans vos fichiers journaux.

Mrki
la source
12

Lorsque vous pointez 499un avortement de connexion enregistré par le nginx. Mais généralement, cela se produit lorsque votre serveur principal est trop lent et qu'un autre proxy expire en premier ou que le logiciel utilisateur abandonne la connexion. Vérifiez donc si uWSGI répond rapidement ou pas s'il y a une charge sur le serveur uWSGI / Database.

Dans de nombreux cas, il existe d'autres proxys entre l'utilisateur et nginx. Certains peuvent être dans votre infrastructure comme peut-être un CDN, Load Balacer, un cache Varnish, etc. D'autres peuvent être du côté utilisateur comme un proxy de mise en cache, etc.

S'il y a des proxys de votre côté comme un LoadBalancer / CDN ... vous devez définir les délais d'expiration pour expirer d'abord votre backend et progressivement les autres proxies vers l'utilisateur.

Si tu as:

user >>> CDN >>> Load Balancer >>> Nginx >>> uWSGI

Je vous recommande de définir:

  • n secondes avant l'expiration de uWSGI
  • n+1 secondes avant l'expiration de nginx
  • n+2 senconds avant l'expiration de Load Balancer
  • n+3 secondes d'expiration du CDN.

Si vous ne pouvez pas définir certains des délais (comme CDN), trouvez quel est son délai et ajustez les autres en fonction de celui-ci ( n, n-1...).

Cela fournit une chaîne correcte de délais d'expiration. et vous trouverez vraiment à qui donner le délai d'expiration et renvoyer le bon code de réponse à l'utilisateur.

Bartomeu
la source
8

Dans mon cas, j'ai obtenu 499 lorsque l'API du client a fermé la connexion avant de recevoir une réponse. Littéralement envoyé un POST et fermez immédiatement la connexion. Ceci est résolu par option:

proxy_ignore_client_abort sur

Nginx doc

DerSkythe
la source
3
Je ne comprends pas comment cela aide
Vladimir Starkov
Ce n'est peut-être pas votre cas? Le client envoie les données et n'est pas intéressé par ce qui va leur arriver et quelle sera la réponse. Mais mon application doit traiter les données. Sans cette option, les données n'ont tout simplement pas le temps d'atteindre mon application.
DerSkythe
Je vous remercie. Symptômes exacts et solution parfaite.
TTimo
Whoa! C'est presque exactement ce dont j'ai besoin. La seule chose que j'ajouterais - serait d'envoyer 200 réponses à la source du webhook un peu avant qu'elle ne ferme la connexion elle-même. Sinon, ils ont tendance à désactiver les webhooks et à ne pas les renvoyer… Puis-je le faire pour les URL sélectionnées?
pilat
1
Cela ne résout pas le problème de votre client qui n'obtient pas de réponse. Il n'élimine que 499 erreurs dans vos journaux et les remplace par le code d'état 200. Mauvaise idée de le faire. La vraie solution est de dire à votre client d'augmenter son délai d'expiration ...
marcinx
7

Il s'avère que 499 signifie vraiment «connexion interrompue par le client».

J'ai eu un délai de lecture client de 60 s (et nginx a également un proxy_read_timeout par défaut de 60 s). Donc, ce qui se passait dans mon cas, c'est que nginx faisait une erreur upstream timed out (110: Connection timed out) while reading upstream. C'est si vous en avez plus d'un.

Ensuite, il essaie le suivant et le suivant jusqu'à ce que (par défaut ) il les ait tous épuisés. Au fur et à mesure que chacun d'eux expire, il les supprime également de la liste des serveurs backend "actifs". Une fois que tout est épuisé, il renvoie un504 gateway timeout.

Donc, dans mon cas, nginx a marqué le serveur comme "indisponible", l'a réessayé sur le serveur suivant, puis le 60sdélai d' expiration de mon client s'est (immédiatement) produit, donc je voyais un upstream timed out (110: Connection timed out) while reading upstreamjournal, immédiatement suivi d'un journal 499. Mais c'était juste une coïncidence de timing.

En relation:

Si tous les serveurs du groupe sont marqués comme actuellement indisponibles, il renvoie également un 502 Bad Gateway.pour 10s. Voir ici max_fails et fail_timeout. Inn les journaux il dirano live upstreams while connecting to upstream.

Si vous n'avez qu'un seul serveur proxy dans votre groupe de serveurs, il essaie simplement le serveur unique et renvoie un 504 Gateway Time-outet ne supprime pas le serveur unique de la liste des serveurs "actifs", s'il proxy_read_timeoutest dépassé. Voir ici "S'il n'y a qu'un seul serveur dans un groupe, les paramètres max_fails, fail_timeout et slow_start sont ignorés, et un tel serveur ne sera jamais considéré comme indisponible."

La partie la plus délicate est que si vous spécifiez proxy_pass à "localhost" et que votre boîte contient également des "versions d'emplacement" ipv6 et ipv4 en même temps (la plupart des boîtes le font par défaut), cela comptera comme si vous aviez une "liste" de plusieurs serveurs dans votre groupe de serveurs, ce qui signifie que vous pouvez vous retrouver dans la situation ci-dessus en lui demandant de renvoyer "502 pendant 10s" même si vous ne listez qu'un seul serveur . Voir ici "Si un nom de domaine se résout en plusieurs adresses, elles seront toutes utilisées de manière circulaire." Une solution de contournement consiste à le déclarer comme proxy_pass http://127.0.0.1:5001;(son adresse ipv4) pour éviter qu'il ne soit à la fois ipv6 et ipv4. Ensuite, il compte comme un comportement "un seul serveur".

Il y a quelques paramètres différents que vous pouvez modifier pour que ce "moins" pose un problème. Comme augmenter les délais d'expiration ou faire en sorte qu'il ne marque pas les serveurs comme "désactivés" lorsqu'ils expirent ... ou corriger la liste pour qu'elle ne soit que de taille 1, voir ci-dessus :)

Voir aussi: https://serverfault.com/a/783624/27813

rogerdpack
la source
3

Cette erreur est assez facile à reproduire en utilisant la configuration standard de nginx avec php-fpm.

Maintenir le bouton F5 enfoncé sur une page créera des dizaines de demandes d'actualisation sur le serveur. Chaque demande précédente est annulée par le navigateur lors d'une nouvelle actualisation. Dans mon cas, j'ai trouvé des dizaines de 499 dans le fichier journal de la boutique en ligne de mon client. D'un point de vue nginx: si la réponse n'a pas été fournie au client avant la prochaine demande d'actualisation, nginx enregistre l'erreur 499.

mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:32 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:33 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:34 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)
mydomain.com.log:84.240.77.112 - - [19/Jun/2018:09:07:35 +0200] "GET /(path) HTTP/2.0" 499 0 "-" (user-agent-string)

Si le traitement php-fpm prend plus de temps (comme une page WP lourde), cela peut bien sûr causer des problèmes. J'ai entendu parler de plantages de php-fpm, par exemple, mais je pense qu'ils peuvent être empêchés de configurer correctement les services, comme le traitement des appels à xmlrpc.php.

Karvonen
la source
2

... est venu ici d'une recherche google

J'ai trouvé la réponse ailleurs ici -> https://stackoverflow.com/a/15621223/1093174

qui devait augmenter le délai d'inactivité de la connexion de mon équilibreur de charge élastique AWS!

(J'avais configuré un site Django avec le proxy inverse nginx / apache, et un travail / une vue de backend vraiment vraiment très log était expiré)

David Lam
la source
0

Une fois que j'ai reçu 499 "La requête a été interdite par l'antivirus" comme réponse AJAX http (faux positif par Kaspersky Internet Security avec une analyse heuristique légère, une analyse heuristique approfondie savait correctement qu'il n'y avait rien de mal).

TeeJay
la source
0

J'ai rencontré ce problème et la cause était due au plugin Kaspersky Protection sur le navigateur. Si vous rencontrez cela, essayez de désactiver vos plugins et voyez si cela résout votre problème.

EGN
la source
0

L'une des raisons de ce comportement pourrait être que vous utilisez httppour uwsgiau lieu de socket. Utilisez la commande ci-dessous si vous utilisez uwsgidirectement.

uwsgi --socket :8080 --module app-name.wsgi

La même commande dans le fichier .ini est

chdir = /path/to/app/folder
socket = :8080
module = app-name.wsgi
Penkey Suresh
la source
0

Cela ne répond pas à la question des OP, mais comme je me suis retrouvé ici après avoir cherché furieusement une réponse, je voulais partager ce que nous avons découvert.

Dans notre cas, il s'avère que ces 499 sont attendus. Lorsque les utilisateurs utilisent la fonction de saisie anticipée dans certaines zones de recherche, par exemple, nous voyons quelque chose comme ça dans les journaux.

GET /api/search?q=h [Status 499] 
GET /api/search?q=he [Status 499]
GET /api/search?q=hel [Status 499]
GET /api/search?q=hell [Status 499]
GET /api/search?q=hello [Status 200]

Donc, dans notre cas, je pense que son utilisation proxy_ignore_client_abort onest sûre, ce qui a été suggéré dans une réponse précédente. Merci pour ça!

Ron DeFulio
la source
0

Pour ma part j'avais activé ufwmais j'ai oublié d'exposer mes ports amont ._.

Alexandre Daubricourt
la source
0

Dans mon cas, j'ai configuré comme

AWS ELB >> ECS(nginx) >> ECS(php-fpm).

J'avais configuré le mauvais groupe de sécurité AWS pour le service ECS (php-fpm), donc Nginx n'a pas pu atteindre le conteneur de tâches php-fpm. C'est pourquoi j'obtenais des erreurs dans le journal des tâches nginx

499 0 - elb-healthchecker/2.0

Le contrôle de santé a été configuré pour vérifier le service php-fpm, confirmer qu'il est actif et renvoyer une réponse.

Piyush Sonigra
la source
0

Je sais que c'est un vieux fil de discussion, mais il correspond exactement à ce qui m'est arrivé récemment et j'ai pensé que je le documenterais ici. La configuration (dans Docker) est la suivante:

  • nginx_proxy
  • nginx
  • php_fpm exécutant l'application réelle.

Le symptôme était un «502 Gateway Timeout» sur l'invite de connexion de l'application. Examen des journaux trouvés:

  • le bouton fonctionne via un HTTP POSTvers /login... et donc ...
  • nginx-proxy a reçu la /logindemande et a finalement signalé un délai d'expiration.
  • nginx a renvoyé une 499réponse, ce qui signifie bien sûr "l'hôte est mort".
  • la /loginrequête n'apparaît pas du tout (!) dans les logs du serveur FPM!
  • il n'y avait pas de tracebacks ou de messages d'erreur dans FPM ... nada, zero, zippo, none.

Il s'est avéré que le problème était un échec de connexion à la base de données pour vérifier la connexion. Mais comment comprendre cela s'est avéré être une pure conjecture.

L'absence totale de journaux de traçabilité des applications ... ou même un enregistrement indiquant que la demande avait été reçue par FPM ... a été une surprise totale (et dévastatrice ...) pour moi. Oui, l'application est censée enregistrer les échecs, mais dans ce cas, il semble que le processus de travail FPM soit mort avec une erreur d'exécution, entraînant la 499réponse de nginx. Maintenant, c'est évidemment un problème dans notre application ... quelque part. Mais je voulais enregistrer les détails de ce qui s'est passé pour le bénéfice des personnes suivantes qui font face à quelque chose comme ça.

Mike Robinson
la source