鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > 网络程序脚本 > 其它 > >

nginx 400状态码排查

来源:互联网 作者:佚名 时间:2014-07-07 07:44
最近,发现主站nginx的log中有很多400的错误,每天有几千万条,故决定对产生400错误的原因进行排查。分析nginxlog,发现这种无效的400请求,总是在一个正常访问

   最近,发现主站nginx的log中有很多400的错误,每天有几千万条,故决定对产生400错误的原因进行排查。分析nginx log,发现这种无效的400请求,总是在一个正常访问之后产生,一般出现一个或者几个。log格式如下:

wKiom1O2bvjzlv3FAAvZ-yla5Cc011.jpg

   

下面对这种情况进行分析:

一,nginx 400状态码含义

A client MUST include a Host header field in all HTTP/1.1 request messages . If the requested URI does not include an Internet host name for the service being requested, then the Host header field MUST be given with an empty value. An HTTP/1.1 proxy MUST ensure that any request message it forwards does contain an appropriate Host header field that identifies the service being requested by the proxy. All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message which lacks a Host header field.

上面是http1.1的rfc关于host部分的解释,从上面我们了解到如果一个http1.1的请求没有host域,那么server应该给client段发送400的状态码,表明这个请求server不能处理。而对于nginx server来说,也遵循这样的方式,说明client发送了一个无效的请求,nginx server无法处理,故返回400的状态码。


参见:

二,重现400请求

1,我使用pc端的chrome和ucweb浏览器,对网站进行访问,发现nginx log中的确会产生400的log,在nginx server端通过netstat看了一下client和server段建立的tcp连接数,每一个请求都是在3个以上。而是用ie和firefox浏览器对网站进行访问,发现不能重现400的log,在nginx server端通过netstat看了一下client和server段建立的tcp连接数,每一个请求都是只有1个。

2,使用telnet登录nginx的80端口

[@zw-81-90 ~]# telnet 10.13.82.96 80
Trying 10.13.82.96...
Connected to 10.13.82.96 (10.13.82.96).
Escape character is '^]'.
Connection closed by foreign host.

使用telnet连接后,直接断开连接即可

三,问题分析

第一种情况:

通过分析nginx的log,发现400请求中chrome和ucweb的ua比较多,通过查看相关的文章发现,这种请求和浏览器的自身策略有关系。

通常我们访问一个网站时,第一个获取的是一个html主文件,而里面链接了网页所需要的css、js、图片等其他媒体资源文件,而一般资源文件和主html文件是在一个域下的,而像chrome这种浏览器就会使用pre-connection,即在获取html之前就与nginx server建立多个的tcp连接,,而不是等到获取到html文件之后再去连接服务器获取这个域名下的其他文件,因为连接服务器是需要消耗一些时间的,所以这项技术可以很大程度上加快网页的呈现速度。当然,浏览器同一时间针对同一域名下的请求也是有一定数量限制。

如果网页html链接的资源比较少,或者客户端有缓存,不需要连接下载,那么Chrome浏览器发出的5-6个连接很可能只有1个是需要的,其他的都得关闭掉,这样就产生了一个问题:连接了服务器,而没有发送任何请求,当然也没有host头了。对于这种情况,nginx是当做400错误来处理的,但由于连接已经关闭,错误信息不会发送到客户端,这就产生了日志文件中记录的400错误。


第二种情况:

使用telnet与nginx server建立个tcp连接,但是没有发送任何数据,当然也没有host头,之后四次挥手断开了连接。这种情况,nginx也是当作400的错误来处理的。使用tcpdump抓包,wireshark分析过程的截图如下:

wKioL1O2bu7hh5itAAQlM54bIYw529.jpg

当然,我们发现使用nagios的check_tcp插件对nginx server端口做检测或者使用keepalived的tcp_check功能对后端nginx端口的存活做检测,这两种情况都会在nginx log中产生400的请求。原因也很简单,就是第二种情况的理由,一般tcp check的方式,就是建立tcp连接,然后再reset或者四次挥手断开连接。

四,解决办法

nginx官方提供了一种方法,使用虚拟主机来匹配那些在nginx上没有匹配到host的请求。这样那些空host的请求,会被这个虚拟主机所匹配。如果不加这个虚拟主机的话,如果nginx上的虚拟主机没有对应client请求的host,nginx默认是用nginx.conf中第一个虚拟主机的处理,故400的请求就会出现在第一个虚拟主机的log中。虚拟主机配置如下:

server {

  listen 80 default_server;

  server_name _;

  return 404;

  access_log off;

}

总之,目前分析来看这类400的无效请求属于正常现象,可以用虚拟主机来消除400的请求。












本文出自 “佳” 博客,请务必保留此出处

上一篇: openVPN 安装
下一篇: Screen简单使用
网友评论
<