NGINX 499错误代码的可能原因


116

我收到很多499个NGINX错误代码。我看到这是一个客户端问题。NGINX或我的uWSGI堆栈都没有问题。我注意到uWSGI日志中的相关性是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

我正在寻找更深入的解释,并希望我的用于uwsgi的NGINX配置没有问题。我认为这是表面价值。似乎是客户问题。


您是否找到了解决方案?我发现uWSGI和nginx都存在完全相同的问题。
拉吉

1
我中止jQuery ajax请求时得到它。
mpen 2014年

1
我知道这是一个非常老的问题,但是在SO上放错位置的问题数量惊人。这显然属于SF。
索苏科多

Answers:


163

Nginx中的HTTP 499意味着客户端在服务器响应请求之前关闭了连接。以我的经验,通常是由客户端超时引起的。据我所知,这是Nginx特定的错误代码。


1
作为一种特殊情况,我注意到有时最终用户双击表单提交按钮时会发生这种情况。该表格发送了两次,但是客户端只期望一个响应。可以通过在第一次单击JS中禁用(至少几秒钟)按钮来解决。
安托万·皮萨德

14
重要的是要注意,“客户端”实际上可能是代理。例如,如果您使用的是负载平衡器,则可能由于超时而取消了对Nginx服务器的请求。
布拉德·科赫

如果用户关闭选项卡并且我的API请求未完成,则它会在我的Angular APP上发生。
Vivek Saurabh

重要的是要注意,这也可能是由服务器引起的;如果服务器花费的时间太长,则客户端放弃。
ijoseph

78

就我而言,我不耐烦,最终误解了日志。

实际上,真正的问题是nginx和uwsgi之间的通信,而不是浏览器和nginx之间的通信。如果将网站加载到浏览器中并且等待了足够长的时间,我将获得“ 504-错误的网关”。但是花了这么长时间,我一直在尝试一些东西,然后在浏览器中刷新。因此,我从来没有等待足够长的时间才能看到504错误。在浏览器中刷新时,即关闭前一个请求时,Nginx在日志中将其写为499。

细化

在这里,我将假设读者对我的了解与我开始玩耍时一样。

我的设置是一个反向代理,即nginx服务器,以及一个应用程序服务器,即其背后的uWSGI服务器。来自客户端的所有请求将发送到nginx服务器,然后转发到uWSGI服务器,然后以相同的方式发送回响应。我认为这是每个人都使用nginx / uwsgi并应该使用它的方式。

我的nginx可以正常工作,但是uwsgi服务器出了点问题。uwsgi服务器可能无法通过两种方式响应nginx服务器。

1)uWSGI说,“我正在处理,请稍候,您很快就会得到答复”。nginx有一定的时间愿意等待20秒钟。之后,它将以504错误响应客户端。

2)uWSGI已死,或者在nginx等待它时uWSGi死亡。nginx立即看到该错误,在这种情况下,它将返回499错误。

我正在通过在客户端(浏览器)中发出请求来测试我的设置。在浏览器中什么也没发生,它一直挂着。大概10秒钟后(少于超时时间),我得出结论说不对(正确),然后从命令行关闭了uWSGI服务器。然后,我将转到uWSGI设置,尝试一些新的操作,然后重新启动uWSGI服务器。关闭uWSGI服务器的那一刻,nginx服务器将返回499错误。

因此,我不断使用499错误进行调试,这意味着需要搜索499错误。但是,如果我等待了足够长的时间,就会收到504错误。如果出现504错误,我将能够更好地理解问题,然后进行调试。

因此得出的结论是,问题一直出在uWGSI身上,它一直挂着(“等一会儿,再等一会儿,那么我会为您提供答案...”)。

我不记得如何解决这个问题。我想这可能是由很多原因引起的。


1
您最终是如何解决这个问题的?我遇到了同样的问题,无法确定原因。
Colin Nichols

1
我添加了详细说明,很遗憾,我认为这不会解决您的问题。
Mads Skjern

1
只想说谢谢!我的情况完全一样,这使我处于正确的轨道。
亚伦

3
@Shafiul:我的阐述没有解释导致uWSGI问题的原因,它只是解释了uWSGI是原因(而非nginx)。详细描述了症状以及我对这些症状的误解。我了解您的失望,但您误解了我回答的实质。真诚的
Mads Skjern

2
极其有用的答案,永不删除!这些概念应该在文档的某个地方得到充实,您可以通过详细说明其行为与文档所暗示的方式来提供出色的服务!
jerclarke

21

客户端关闭连接并不意味着这是浏览器问题!?一点也不!

如果您的Web服务器(nginx)前面有LB(负载均衡器)AWS或haproxy(自定义),则可以在日志文件中找到499个错误。也就是说,LB将充当nginx的客户端。

如果您为以下内容运行haproxy默认值:

    timeout client  60000
    timeout server  60000

这意味着如果nginx没有响应,则LB将在60000ms之后超时。对于繁忙的网站或需要更多时间执行的脚本,可能会发生超时。您需要找到适合您的超时时间。例如,将其扩展到:

    timeout client  180s
    timeout server  180s

而且您可能会被设置。

根据您的设置,您可能会在浏览器中看到504网关超时错误,这表明php-fpm出了点问题,但日志文件中有499错误的情况就不是这种情况。


12

正如您指出499的那样,nginx记录了连接中止。但是通常这是由于您的后端服务器太慢导致的,并且另一个代理首先超时或用户软件中止连接。因此,请检查uWSGI是否正在快速响应,或者uWSGI /数据库服务器上是否有负载。

在许多情况下,用户和Nginx之间还有其他一些代理。有些可以在您的基础结构中,例如CDN,Load Balacer,Varnish缓存等。其他则可以在用户端,例如缓存代理等。

如果您身边有代理,例如LoadBalancer / CDN ...,则应将超时设置为先使后端超时,然后将其他代理逐步超时。

如果你有:

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

我建议您设置:

  • n uWSGI超时的秒数
  • n+1 秒到Nginx超时
  • n+2 超时到负载均衡器
  • n+3 CDN超时的秒数。

如果您无法设置某些超时(例如CDN),请找出它的超时,然后根据它来调整其他超时(nn-1...)。

这提供了正确的超时链。您会发现真正的超时原因是谁,并向用户返回正确的响应代码。


8

就我而言,当客户端的API在获得任何响应之前关闭连接时,我得到了499。从字面上发送POST,并立即关闭连接。这可以通过选项解决:

proxy_ignore_client_abort在

Nginx文档


3
我不知道这有什么帮助
弗拉基米尔·斯塔科夫(Fladimir Starkov)

也许不是你的情况?客户端发送数据,对它们将发生什么以及答案将不感兴趣。但是我的应用程序应该处理数据。如果没有此选项,数据将根本没有时间到达我的应用程序。
DerSkythe

谢谢。确切的症状和完美的解决方法。
TTimo

哇!那几乎就是我所需要的。我唯一要添加的-是关闭连接本身之前向webhook源发送200个响应。否则,它们往往会禁用Webhook,并且不会再次发送它们……对于所选的URL,我可以这样做吗?
彼拉特,

1
这不能解决您的客户没有得到答复的问题。它只能消除日志中的499个错误,并将其替换为状态码200。这样做的坏主意。真正的解决方案是告诉您的客户增加其超时设置...
marcinx

7

事实证明499确实确实意味着“客户端中断连接”。

我的客户端读取超时为60s(nginx也具有默认的60s的proxy_read_timeout)。因此,在我的情况下,nginx会出错。请登录an upstream timed out (110: Connection timed out) while reading upstream,然后nginx重试“您配置的后端服务器组中的下一个代理服务器”。那就是如果您有多个。

然后,它尝试下一个和下一个直到(默认)用尽所有它们。每次超时时,也会将它们从“活动的”后端服务器列表中删除。精疲力尽后,它返回一个504 gateway timeout.

因此,在我的情况下,nginx将服务器标记为“不可用”,在下一个服务器上重新尝试,然后60s(立即)发生了客户端的超时,因此我会看到一条upstream timed out (110: Connection timed out) while reading upstream日志,紧接着是499日志。但这只是时间巧合。

有关:

如果组中的所有服务器都标记为当前不可用,则它502 Bad Gateway.也会返回10s。请参阅此处 max_fails和fail_timeout。记录日志中的内容no live upstreams while connecting to upstream.

如果服务器组中只有一个代理后端,则仅尝试使用一504 Gateway Time-out台服务器,如果proxy_read_timeout超过则返回a 并且不会从“活动”服务器列表中删除该服务器。看到此处: “如果组中只有一台服务器,则将忽略max_fails,fail_timeout和slow_start参数,并且永远不会认为这样的服务器不可用。”

真正棘手的部分是,如果您将proxy_pass指定为“ localhost”,并且您的框上恰好同时具有ipv6和ipv4“位置版本”(大多数框默认情况下都执行),则将其视为服务器组中多个服务器的“列表”,这意味着即使您只列出一台服务器,也可以进入上述情况,使其返回“ 502 for 10s” 。请参阅此处 “如果一个域名解析为多个地址,则所有这些地址都将以循环方式使用。” 一种解决方法是将其声明为proxy_pass http://127.0.0.1:5001;(其ipv4地址)以避免同时使用ipv6和ipv4。然后将其视为“仅单个服务器”行为。

您可以调整一些不同的设置来解决这个“问题”。就像增加超时或使其超时一样,以便在服务器超时时不会将服务器标记为“已禁用” ...或修复列表,使其只有大小1,请参见上文:)

另请参阅:https : //serverfault.com/a/783624/27813


3

使用带有php-fpm的标准nginx配置,很容易重现此错误。

在页面上按住F5键将向服务器创建数十个刷新请求。浏览器在重新刷新时会取消每个先前的请求。就我而言,我在客户的在线商店日志文件中找到了499个。从nginx的角度来看:如果在下一个刷新请求之前尚未将响应传递给客户端,nginx将记录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)

当然,如果php-fpm处理花费的时间更长(如较重的WP页面),则可能会导致问题。例如,我听说过php-fpm崩溃,但是我相信可以防止它们正确配置服务,例如处理对xmlrpc.php的调用。


2

...来自谷歌搜索

我在这里的其他地方找到了答案-> https://stackoverflow.com/a/15621223/1093174

这是为了提高我的AWS弹性负载均衡器的连接空闲超时!

(我已经用nginx / apache反向代理设置了Django站点,并且一个非常真正的日志后端作业/视图正在超时)


0

一旦获得499作为AJAX http响应的“请求已被防病毒软件禁止”(卡巴斯基Internet Security的误判为轻度启发式分析,深度启发式分析就知道没有错)。


0

我遇到此问题,原因是由于浏览器上的Kaspersky Protection插件。如果遇到此问题,请尝试禁用您的插件,看看是否能解决您的问题。


0

出现这种现象的原因之一可能是您使用httpfor uwsgi代替socket。如果uwsgi直接使用,请使用以下命令。

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

.ini文件中的相同命令是

chdir = /path/to/app/folder
socket = :8080
module = app-name.wsgi

0

这不能回答OP的问题,但是由于我在疯狂地寻找答案后来到了这里,所以我想分享我们发现的内容。

在我们的案例中,事实证明这499个是预期的。例如,当用户在某些搜索框中使用预输入功能时,我们会在日志中看到类似的内容。

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]

因此,在我们的案例中,我认为它的使用安全性proxy_ignore_client_abort on已在先前的答案中提出。感谢那!



0

就我而言,我的设置

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

我为ECS(php-fpm)服务配置了错误的AWS安全组,因此Nginx无法访问php-fpm任务容器。这就是为什么我在Nginx任务日志中遇到错误的原因

499 0 - elb-healthchecker/2.0

运行状况检查已配置为检查php-fpm服务,并确认它已启动并返回响应。


0

我知道这是一个旧线程,但是它与最近发生在我身上的事情完全匹配,我认为我将在这里进行记录。设置(在Docker中)如下:

  • nginx_proxy
  • Nginx的
  • php_fpm运行实际的应用程序。

症状是在应用程序登录提示符下显示“ 502网关超时”。检查发现的日志:

  • 该按钮通过HTTP POST/login... 起作用,所以...
  • nginx-proxy得到了 /login请求,并最终报告了超时。
  • nginx返回了一个499响应,这当然意味着“主机已死”。
  • /login请求根本没有出现在 FPM服务器的日志中!
  • FPM中没有回溯或错误消息... nada,零,zippo,无。

原来,问题是无法连接到数据库以验证登录名。但是如何弄清楚事实证明这纯粹是猜测。

完全没有应用程序回溯日志……甚至没有FPM收到请求的记录……对我来说是一个完整的(并且是毁灭性的……)惊喜。是的,该应用程序应该记录故障,但是在这种情况下,FPM工作进程似乎因运行时错误499而终止,从而导致nginx做出响应。现在,这显然是我们应用程序中的一个问题。但是我想记录下发生的细节,以使下一个面对这种事情的人受益。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.