Möglicher Grund für NGINX 499-Fehlercodes

116

Ich erhalte viele 499 NGINX-Fehlercodes. Ich sehe, dass dies ein clientseitiges Problem ist. Es ist kein Problem mit NGINX oder meinem uWSGI-Stack. Ich stelle die Korrelation in uWSGI-Protokollen fest, wenn ein 499 erhalten wird.

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

Ich suche nach einer ausführlicheren Erklärung und hoffe, dass mit meiner NGINX-Konfiguration für uwsgi nichts falsch ist. Ich nehme es auf den Nennwert. Es scheint ein Kundenproblem zu sein.

Tampa
quelle
Haben Sie jemals eine Lösung dafür gefunden? Ich sehe genau das gleiche Problem mit uWSGI und nginx.
Raj
1
Ich bekomme es, wenn ich eine jQuery-Ajax-Anfrage abbreche.
Mpen
1
Ich weiß, dass dies eine sehr alte Frage ist, aber die Anzahl der falsch platzierten Fragen zu SO ist atemberaubend. Dies gehört eindeutig zu SF.
Sosukodo

Antworten:

162

HTTP 499 in Nginx bedeutet, dass der Client die Verbindung geschlossen hat, bevor der Server die Anforderung beantwortet hat. Nach meiner Erfahrung wird dies normalerweise durch ein clientseitiges Timeout verursacht . Wie ich weiß, handelt es sich um einen Nginx-spezifischen Fehlercode.

mrbo
quelle
1
Als Sonderfall habe ich festgestellt, dass es manchmal vorkommt, wenn der Endbenutzer auf eine Schaltfläche zum Senden eines Formulars doppelklickt. Das Formular wird zweimal gesendet, aber vom Client wird nur eine Antwort erwartet. Dies kann umgangen werden, indem die Schaltflächen in JS (zumindest für einige Sekunden) beim ersten Klicken deaktiviert werden.
Antoine Pinsard
13
Es ist wichtig zu beachten, dass der "Client" tatsächlich ein Proxy sein kann. Wenn Sie beispielsweise einen Load Balancer verwenden, wird die Anforderung an den Nginx-Server möglicherweise aufgrund eines Zeitlimits abgebrochen.
Brad Koch
Dies geschieht in meiner Angular-App, wenn der Benutzer die Registerkarte schließt und meine API-Anforderungen nicht abgeschlossen werden.
Vivek Saurabh
Es ist wichtig zu beachten, dass dies auch vom Server verursacht werden kann . Wenn der Server zu lange braucht, um zu antworten, gibt der Client auf.
Ijoseph
77

In meinem Fall war ich ungeduldig und habe das Protokoll falsch interpretiert.

Tatsächlich war das eigentliche Problem die Kommunikation zwischen nginx und uwsgi und nicht zwischen dem Browser und nginx. Wenn ich die Site in meinen Browser geladen und lange genug gewartet hätte, hätte ich ein "504 - Bad Gateway" bekommen. Aber es hat so lange gedauert, dass ich immer wieder Dinge ausprobiert und dann im Browser aktualisiert habe. Ich habe also nie lange genug gewartet, um den 504-Fehler zu sehen. Beim Aktualisieren im Browser wird die vorherige Anforderung geschlossen, und Nginx schreibt dies als 499 in das Protokoll.

Ausarbeitung

Hier gehe ich davon aus, dass der Leser so wenig weiß wie ich, als ich anfing herumzuspielen.

Mein Setup war ein Reverse-Proxy, der Nginx-Server, und ein Anwendungsserver, der dahinter stehende uWSGI-Server. Alle Anforderungen vom Client wurden an den Nginx-Server gesendet, dann an den uWSGI-Server weitergeleitet, und die Antwort wurde auf dieselbe Weise zurückgesendet. Ich denke, so benutzt jeder Nginx / Uwsgi und soll es benutzen.

Mein Nginx hat so funktioniert, wie es sollte, aber mit dem uwsgi-Server stimmte etwas nicht. Es gibt zwei Möglichkeiten (möglicherweise mehr), auf die der uwsgi-Server möglicherweise nicht auf den nginx-Server reagiert.

1) uWSGI sagt: "Ich verarbeite, warte nur und du wirst bald eine Antwort erhalten." nginx hat eine bestimmte Zeitspanne, die es zu warten bereit ist, fx 20 Sekunden. Danach antwortet es dem Client mit einem 504-Fehler.

2) uWSGI ist tot oder uWSGi stirbt, während nginx darauf wartet. nginx sieht das sofort und gibt in diesem Fall einen 499-Fehler zurück.

Ich habe mein Setup getestet, indem ich Anfragen im Client (Browser) gestellt habe. Im Browser passierte nichts, es hing einfach weiter. Nach vielleicht 10 Sekunden (weniger als das Timeout) kam ich zu dem Schluss, dass etwas nicht stimmte (was wahr war), und schloss den uWSGI-Server über die Befehlszeile. Dann würde ich zu den uWSGI-Einstellungen gehen, etwas Neues ausprobieren und dann den uWSGI-Server neu starten. In dem Moment, in dem ich den uWSGI-Server geschlossen habe, hat der Nginx-Server einen 499-Fehler zurückgegeben.

Also habe ich weiter mit dem 499-Fehler debuggt, was bedeutet, nach dem 499-Fehler zu googeln. Aber wenn ich lange genug gewartet hätte, hätte ich den 504-Fehler bekommen. Wenn ich den 504-Fehler erhalten hätte, hätte ich das Problem besser verstehen und dann debuggen können.

Die Schlussfolgerung ist also, dass das Problem bei uWGSI lag, das immer wieder hängen blieb ("Warte ein bisschen länger, nur ein bisschen länger, dann werde ich eine Antwort für dich haben ...").

Wie ich dieses Problem behoben habe , weiß ich nicht mehr. Ich denke, es könnte durch viele Dinge verursacht werden.

Mads Skjern
quelle
1
Wie haben Sie das gelöst? Ich habe das gleiche Problem und konnte die Ursache nicht feststellen.
Colin Nichols
1
Ich habe eine Ausarbeitung hinzugefügt, leider glaube ich nicht, dass sie Ihr Problem lösen wird.
Mads Skjern
1
Ich wollte mich nur bedanken! Ich hatte genau die gleiche Situation und das brachte mich auf den richtigen Weg.
Aaron
3
@Shafiul: Meine Ausarbeitung erklärt nicht, was das Problem mit uWSGI verursacht hat, sondern erklärt einfach, dass uWSGI die Ursache war (und nicht Nginx). Die Ausarbeitung beschreibt die Symptome und wie ich diese falsch interpretiert habe. Ich verstehe Ihre Enttäuschung, aber Sie haben das Wesentliche meiner Antwort falsch verstanden. Mit freundlichen Grüßen.
Mads Skjern
2
Sehr nützliche Antwort, niemals löschen! Diese Konzepte sollten irgendwo in der Dokumentation konkretisiert werden. Sie leisten einen großartigen Dienst, indem Sie herausfinden, wie sie sich anders verhalten, als es die Dokumente implizieren würden!
Jerclarke
21

Client hat die Verbindung geschlossen bedeutet nicht, dass es sich um ein Browserproblem handelt!? Überhaupt nicht!

Sie können 499 Fehler in einer Protokolldatei finden, wenn Sie einen LB (Load Balancer) vor Ihrem Webserver (Nginx) haben, entweder AWS oder Haproxy (benutzerdefiniert). Die LB wird jedoch als Kunde für nginx fungieren.

Wenn Sie Haproxy-Standardwerte für Folgendes ausführen:

    timeout client  60000
    timeout server  60000

Das würde bedeuten, dass LB nach 60000 ms eine Zeitüberschreitung aufweist, wenn keine Antwort von nginx erfolgt. Bei ausgelasteten Websites oder Skripten, die mehr Zeit für die Ausführung benötigen, können Zeitüberschreitungen auftreten. Sie müssen eine Zeitüberschreitung finden, die für Sie funktioniert. Erweitern Sie es beispielsweise auf:

    timeout client  180s
    timeout server  180s

Und Sie werden wahrscheinlich eingestellt sein.

Abhängig von Ihrem Setup wird in Ihrem Browser möglicherweise ein 504-Gateway-Timeout-Fehler angezeigt, der darauf hinweist, dass mit php-fpm etwas nicht stimmt. Bei 499-Fehlern in Ihren Protokolldateien ist dies jedoch nicht der Fall.

mrki
quelle
11

Wenn Sie auf 499einen vom Nginx protokollierten Verbindungsabbruch hinweisen . In der Regel wird dies jedoch erzeugt, wenn Ihr Backend-Server zu langsam ist und zuerst ein anderes Proxy-Timeout auftritt oder die Benutzersoftware die Verbindung abbricht. Überprüfen Sie daher, ob uWSGI schnell antwortet oder nicht, ob der uWSGI / Datenbankserver belastet ist.

In vielen Fällen gibt es einige andere Proxys zwischen dem Benutzer und nginx. Einige können sich in Ihrer Infrastruktur befinden, z. B. ein CDN, ein Load Balacer, ein Lack-Cache usw. Andere können sich auf der Benutzerseite befinden, z. B. ein Caching-Proxy usw.

Wenn sich auf Ihrer Seite Proxys wie ein LoadBalancer / CDN befinden ... sollten Sie die Zeitüberschreitungen so einstellen, dass zuerst Ihr Backend und nach und nach die anderen Proxys für den Benutzer eine Zeitüberschreitung aufweisen.

Wenn Sie haben:

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

Ich empfehle Ihnen, Folgendes einzustellen:

  • n Sekunden bis zum uWSGI-Timeout
  • n+1 Sekunden bis Nginx Timeout
  • n+2 Sekunden bis zum Timeout für Load Balancer
  • n+3 Sekunden Timeout zum CDN.

Wenn Sie einige der Zeitüberschreitungen (wie CDN) nicht festlegen können, suchen Sie nach der Zeitüberschreitung und passen Sie die anderen entsprechend an ( n, n-1...).

Dies bietet eine korrekte Kette von Zeitüberschreitungen. und Sie werden wirklich feststellen, wer das Timeout angibt und den richtigen Antwortcode an den Benutzer zurückgibt.

Bartomeu
quelle
8

In meinem Fall habe ich 499 erhalten, als die Client-API die Verbindung geschlossen hat, bevor sie eine Antwort erhält. Senden Sie buchstäblich einen POST und schließen Sie sofort die Verbindung. Dies wird durch Option gelöst:

proxy_ignore_client_abort on

Nginx doc

DerSkythe
quelle
3
Ich verstehe nicht, wie das hilft
Vladimir Starkov
Vielleicht ist es nicht dein Fall? Der Kunde sendet die Daten und ist nicht daran interessiert, was mit ihm geschehen wird und was die Antwort sein wird. Aber meine Bewerbung sollte die Daten verarbeiten. Ohne diese Option haben die Daten einfach keine Zeit, meine Anwendung zu erreichen.
DerSkythe
Danke dir. Genaue Symptome und perfekte Lösung.
TTimo
Whoa! Das ist fast genau das, was ich brauche. Das einzige, was ich hinzufügen möchte, wäre, 200 Antworten ein wenig an die Webhook-Quelle zu senden, bevor die Verbindung selbst geschlossen wird. Andernfalls deaktivieren sie Webhooks und senden sie nicht erneut. Kann ich dies für ausgewählte URLs tun?
Pilat
1
Dies löst nicht das Problem, dass Ihr Kunde keine Antwort erhält. Es werden nur 499 Fehler in Ihren Protokollen beseitigt und durch den Statuscode 200 ersetzt. Schlechte Idee, dies zu tun. Die wirkliche Lösung besteht darin, Ihren Kunden
anzuweisen,
7

Es stellt sich heraus, dass 499 wirklich "Client unterbrochene Verbindung" bedeutet.

Ich hatte ein Client-Lesezeitlimit von 60s (und nginx hat auch ein Standard-Proxy_read_timeout von 60s). In meinem Fall passierte also, dass nginx error.log an upstream timed out (110: Connection timed out) while reading upstreamund dann versucht nginx erneut "den nächsten Proxyserver in der von Ihnen konfigurierten Backend- Servergruppe ". Das ist, wenn Sie mehr als eine haben.

Dann versucht es das nächste und nächste, bis ( standardmäßig ) alle erschöpft sind. Bei jeder Zeitüberschreitung werden sie auch aus der Liste der "Live" -Backend-Server entfernt. Nachdem alle erschöpft sind, gibt es a zurück504 gateway timeout.

In meinem Fall hat nginx den Server als "nicht verfügbar" markiert, ihn auf dem nächsten Server erneut versucht. Dann trat das 60sZeitlimit meines Clients (sofort) auf, sodass ein upstream timed out (110: Connection timed out) while reading upstreamProtokoll angezeigt wurde, unmittelbar gefolgt von einem 499-Protokoll. Aber es war nur ein zeitlicher Zufall.

Verbunden:

Wenn alle Server in der Gruppe als derzeit nicht verfügbar markiert sind, wird ebenfalls ein 502 Bad Gateway.Wert für 10 Sekunden zurückgegeben. Siehe hier max_fails und fail_timeout. In den Protokollen wird es sagenno live upstreams while connecting to upstream.

Wenn Sie nur ein Proxy-Backend in Ihrer Servergruppe haben, versuchen Sie es einfach mit dem einen Server und geben einen zurück 504 Gateway Time-outund entfernen den einzelnen Server nicht aus der Liste der "Live" -Server, wenn er proxy_read_timeoutüberschritten wird. Siehe hier "Wenn nur ein einziger Server in einer Gruppe vorhanden ist, werden die Parameter max_fails, fail_timeout und slow_start ignoriert, und ein solcher Server wird niemals als nicht verfügbar angesehen."

Der wirklich knifflige Teil ist, dass, wenn Sie proxy_pass für "localhost" angeben und Ihre Box zufällig gleichzeitig ipv6- und ipv4-Versionen des Speicherorts enthält (die meisten Boxen tun dies standardmäßig), dies so zählt, als ob Sie es getan hätten Eine "Liste" mehrerer Server in Ihrer Servergruppe. Dies bedeutet, dass Sie in die oben beschriebene Situation geraten können, wenn "502 für 10 Sekunden" zurückgegeben wird, obwohl Sie nur einen Server auflisten . Siehe hier "Wenn ein Domain-Name in mehrere Adressen aufgelöst wird, werden alle im Round-Robin-Verfahren verwendet." Eine Problemumgehung besteht darin, es als proxy_pass http://127.0.0.1:5001;(seine IPv4-Adresse) zu deklarieren , um zu vermeiden , dass es sowohl IPv6 als auch IPv4 ist. Dann zählt es als "nur ein einziger Server" -Verhalten.

Es gibt ein paar verschiedene Einstellungen, die Sie anpassen können, um dieses Problem "weniger" zu machen. Wie das Erhöhen von Zeitüberschreitungen oder das Festlegen, dass Server beim Zeitlimit nicht als "deaktiviert" markiert werden ... oder das Korrigieren der Liste, sodass sie nur Größe 1 hat, siehe oben :)

Siehe auch: https://serverfault.com/a/783624/27813

Rogerdpack
quelle
3

Dieser Fehler ist mit der Standard-Nginx-Konfiguration mit php-fpm ziemlich einfach zu reproduzieren.

Wenn Sie die Taste F5 auf einer Seite gedrückt halten, werden Dutzende von Aktualisierungsanforderungen an den Server erstellt. Jede vorherige Anforderung wird vom Browser bei einer neuen Aktualisierung abgebrochen. In meinem Fall habe ich Dutzende von 499 in der Online-Shop-Protokolldatei meines Kunden gefunden. Aus Nginx-Sicht: Wenn die Antwort nicht vor der nächsten Aktualisierungsanforderung an den Client übermittelt wurde, protokolliert Nginx den 499-Fehler.

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)

Wenn die PHP-Fpm-Verarbeitung länger dauert (wie bei einer umfangreichen WP-Seite), kann dies natürlich zu Problemen führen. Ich habe zum Beispiel von PHP-Fpm-Abstürzen gehört, aber ich glaube, dass sie daran gehindert werden können, Dienste richtig zu konfigurieren, wie z. B. die Bearbeitung von Aufrufen an xmlrpc.php.

Karvonen
quelle
2

... kam von einer Google-Suche hierher

Ich habe die Antwort an anderer Stelle hier gefunden -> https://stackoverflow.com/a/15621223/1093174

Das sollte das Verbindungsleerlauf-Timeout meines elastischen AWS-Lastausgleichs erhöhen!

(Ich hatte eine Django-Site mit Nginx / Apache-Reverse-Proxy eingerichtet, und ein wirklich, wirklich, wirklich Log-Backend-Job / eine Ansicht lief ab.)

David Lam
quelle
0

Nachdem ich 499 "Anfrage wurde durch Antivirus verboten" als AJAX-http-Antwort erhalten hatte (falsch positiv von Kaspersky Internet Security mit leichter heuristischer Analyse, tiefe heuristische Analyse wusste richtig, dass nichts falsch war).

TeeJay
quelle
0

Ich bin auf dieses Problem gestoßen und die Ursache war das Kaspersky Protection-Plugin im Browser. Wenn dies auftritt, versuchen Sie, Ihre Plugins zu deaktivieren, und prüfen Sie, ob das Problem dadurch behoben wird.

EGN
quelle
0

Einer der Gründe für dieses Verhalten könnte sein , Sie verwenden httpfür uwsgistatt socket. Verwenden Sie den folgenden Befehl, wenn Sie uwsgidirekt verwenden.

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

Der gleiche Befehl in der INI-Datei lautet

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

Dies beantwortet die OP-Frage nicht, aber da ich hier gelandet bin, nachdem ich wütend nach einer Antwort gesucht hatte, wollte ich mitteilen, was wir entdeckt haben.

In unserem Fall stellt sich heraus, dass diese 499 erwartet werden. Wenn Benutzer beispielsweise in einigen Suchfeldern die Funktion "Vorausschreiben" verwenden, wird in den Protokollen Folgendes angezeigt.

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]

In unserem Fall denke ich, dass es sicher zu verwenden ist, proxy_ignore_client_abort onwas in einer früheren Antwort vorgeschlagen wurde. Dank dafür!

Ron DeFulio
quelle
0

Ich für meinen Teil hatte aktiviert, ufwaber ich habe vergessen, meine Upstream-Ports freizulegen ._.

Alexandre Daubricourt
quelle
0

In meinem Fall habe ich wie eingerichtet

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

Ich hatte die falsche AWS-Sicherheitsgruppe für den ECS-Dienst (php-fpm) konfiguriert, sodass Nginx nicht in der Lage war, den PHP-fpm-Aufgabencontainer zu erreichen. Deshalb habe ich Fehler im Nginx-Aufgabenprotokoll bekommen

499 0 - elb-healthchecker/2.0

Die Integritätsprüfung wurde so konfiguriert, dass der PHP-Fpm-Dienst überprüft und bestätigt wird, dass er aktiv ist, und eine Antwort zurückgegeben wird.

Piyush Sonigra
quelle
0

Ich weiß, dass dies ein alter Thread ist, aber er passt genau zu dem, was mir kürzlich passiert ist, und ich dachte, ich würde ihn hier dokumentieren. Das Setup (in Docker) ist wie folgt:

  • nginx_proxy
  • Nginx
  • php_fpm mit der eigentlichen App.

Das Symptom war ein "502 Gateway Timeout" an der Anmeldeaufforderung der Anwendung. Prüfung der gefundenen Protokolle:

  • Die Schaltfläche funktioniert über ein HTTP POSTzu /login... und so ...
  • nginx-proxy hat die /loginAnfrage erhalten und schließlich eine Zeitüberschreitung gemeldet.
  • nginx gab eine 499Antwort zurück, was natürlich bedeutet, dass "der Host gestorben ist".
  • Die /loginAnfrage wurde überhaupt nicht (!) in den Protokollen des FPM-Servers angezeigt!
  • Es gab keine Tracebacks oder Fehlermeldungen in FPM ... nada, zero, zippo, none.

Es stellte sich heraus, dass das Problem darin bestand, dass keine Verbindung zur Datenbank hergestellt werden konnte, um die Anmeldung zu überprüfen. Aber wie man das herausfindet, stellte sich als reine Vermutung heraus.

Das völlige Fehlen von Traceback-Protokollen für Anwendungen ... oder sogar eine Aufzeichnung, dass die Anfrage bei FPM eingegangen war ... war für mich eine völlige (und verheerende ...) Überraschung. Ja, die Anwendung soll Fehler protokollieren, aber in diesem Fall scheint der FPM-Worker-Prozess mit einem Laufzeitfehler gestorben zu sein, der zur 499Antwort von nginx führte. Dies ist offensichtlich ein Problem in unserer Anwendung ... irgendwo. Aber ich wollte die Einzelheiten dessen aufzeichnen, was zugunsten der nächsten Leute passiert ist, die mit so etwas konfrontiert sind.

Mike Robinson
quelle