目录
- 目录
- 前言
- 坏境搭建
- http状态码分类
- 请求错误类(客户端错误)
- 400
- 401
- 403
- 404
- 405
- 413
- 414
- 499(nginx status)
- 服务端错误
- 500
- 502
- 503
- 504
- 重定向和缓存
- 301和302
- 304
前言
本文目的旨在对http状态码含义做一个基本解释,不会太深入讨论每个状态码,由于每个http状态码的出现可能对应多种情况,本文可能也考虑不周全。总之,看完本文,能够对http状态码有一个更加直观的认知。本文的思路是一个状态码加一个重现例子的方式呈现。
坏境搭建
本文的测试需要的linux+nginx+PHP环境,可以不需要MySQL。搭建环境的资料如下:
lnmp.zip
http状态码分类
- 消息类(1字头)
- 成功类(2字头)
- 重定向类(3字头)
- 请求错误类(4字头)
- 服务器错误类(5、6字头)
中途可能会穿插nginx自定义的http状态码,nginx状态码本身不属于http状态码了,只是在nginx内部自己定义的一套状态码,但是在nginx日志中,却经常出现
请求错误类(客户端错误)
400
400的英文含义400 Request Header Or Cookie Too Large
,顾名思义,头信息或者Cookie信息太多了
复现这个状态码只需要添加够长的头信息或者Cookie信息即可,构造一个curl请求:
curl --header "Cookie:sidisisidisidisisidisidisisidisidisisidisidisisidisidisisidisidisidisisidisisidisidisisidisidisisidisidisisidisidisisidisidisisidisidissidisisidisidisisidisidisisidisidisisidisidisisidisidisisidisidissidisisidisidisisidisidisisidisidisisidisidisisidisidisisidisidissidisisidisidisisidisidisisidisidisisidisidisisidisidisisidisidissidisisidisidisisidisidisisidisidisisidisidisisidisidisisi....." http://localhost:80
401
401的含义是401 Authorization Required
,顾名思义,就是需要权限认证,但是客户端又没有通过认证。复现这个状态码必须对nginx调整成认证模式。现在,将nginx调成认证模式,nginx的server模块配置如下
location / {
auth_basic "secret";#认证模式
auth_basic_user_file /usr/local/nginx/passwd.db;#密码文件
root html2;
index index.html index.htm;
}
接下来生成密码文件
sh-3.2# htpasswd -c /usr/local/nginx/passwd.db yongxiongzhong
New password:
Re-type new password:
Adding password for user yongxiongzhong
更改权限
chmod 400 /usr/local/nginx/passwd.db
平滑重启nginx之后,再次访问网页可以看到认证界面
点击取消按钮,则可以看到以下这个页面
403
403的出现,大部分是没有对文件进行授权。403 Forbidden
顾名思义就是禁止访问,重现这个状态码只需要修改访问文件的权限,比如给nginx网站根目录中的index文件减少权限
chmod 0 /usr/local/nginx/html/index.html
404
404算是我们经常碰到的状态码,404 Not Found
当我们访问一个不存在的文件时,就会出现这个错误
在URL地址栏上随便访问一个不存在的文件,就会出现
在实际生产环境中,这样的404页面并不好看,所以可以通过在server中配置自定义404页面:
error_page 404 /my_404.html;
其中在网站根目录新建my_404.html然后写入自定义内容。平滑重启nginx之后,再次访问一些不存在的页面时会提示如下:
405
405状态码并不算常见,它表示405 Not Allowed
。http请求可以支持GET,POST,PUT,DELETE方式。默认情况下,如果你对一个html静态文件进行post请求的话,就会出现405错误
413
413也是比较容易出现的一种状态码,413的出现常常伴随着413 Request Entity Too Large
表示请求实体过大导致。用户上传的Content-Length大于nginx设定的最大值时。比如上传一张很大的图片,就会出现413错误码
这个是由参数client_max_body_size控制的,默认是1M。有点小,所以一般线上环境调成以下配置即可消除上面的问题
client_max_body_size 8m;
414
一般出现这个错误的时候,也伴随着一段英文提示414 Request-URI Too Large
,也就是说我们请求的url太长了,如果我们把一个很长的url放在浏览器地址栏上,浏览器的保护措施,并不会出现414报错。所以要重现这个414错误码,只能通过curl命令。申请如下一个很长的url,篇幅问题,最后用…代替:
curl http://localhost:8080/?key=abcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefgabcdefg....
运行这个curl命令,就可以看到414错误
在nginx中,以下两个参数共同决定这个问题
client_header_buffer_size
large_client_header_buffers
499(nginx status)
499这个状态码并不是http协议中定义的status code,而是nginx自己定义的一个状态码。
当客户端主动断开连接的时候,nginx就会返回499的状态码。按照这个状态码的定义,复现这个状态码很容易,只要在nginx返回结果之前断开客户端连接。所以,下一个data.php文件
php
sleep(10);//睡觉10秒钟
然后在浏览器访问http://localhost:8000/data.php,注意,在10秒之内关闭浏览器以断开客户端连接。然后在查看nginx访问日志就能看到499错误
值得一提的是,在线上环境中,如果并发量大的话,nginx未能及时处理完请求,导致客户端“不干了”,这是会大量爆发499错误。这种情况可以用ab工具测试,ab工具中,-n为请求次数,-c为并发量:
ab -n 100 -c 100 http://127.0.0.1:8000/data.php
服务端错误
500
http状态码500表示内部服务器错误,这个错误一般是php代码出现error导致,如果你没有关闭php错误提示,当写一个错误的php脚本时,网页上会出现以下错误提示
但是一般情况下这些错误我们并不希望就这样暴露给客户端,因为将这些错误信息暴露是一件很危险的事情,别人可以通过你的错误猜测系统漏洞。所以在线上一般是关闭错误显示,关闭方式为:编辑php-fpm.conf关闭错误信息,保存php-fpm以下设置项
php_flag[display_errors] = off
平滑重启php-fpm进程之后,再次访问一个包含错误语法的php错误的时候,会报500错误。
502
当出现502这个错误的时候,也伴随着一句英文502 bad geteway
,很醒目的一段问题,出现这个错误的时候,因为这是服务端错误,可以定位挂掉了
。Nginx 502错误的原因比较多,是因为在代理模式下后端服务器出现问题引起的。这些错误一般都不是nginx本身的问题,一定要从后端找原因。比如这里复现一种后端php-fpm进程挂掉的情况,关闭php-fpm
kill -9 `ps aux | grep php-fpm | grep -v grep | awk -F ' ' '{print $2}'`
503
注意,出现503的时候服务没挂,出现503的时候伴随着503 Service Temporarily Unavailable
,这句话告诉我们服务是暂时性不可用,nginx官方文档上有说明这一点,
Sets the shared memory zone and the maximum allowed number of connections for a given key value. When this limit is exceeded, the server will return the 503 (Service Temporarily Unavailable) error in reply to a request.
简单的说,就是在控制请求频率和并发数,详细配置可以参考nginx官方文档:http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html#limit_conn
这里只复现一种可能的情况,将nginx配置如下(两个核心配置,省去了很多):
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
limit_conn addr 1;#并发数为1,好测试
注意测试的时候,不是所有的连接都算进去,也就是并发数为1,并不代表只能并发1,nginx说明:
Not all connections are counted. A connection is counted only if it has a request processed by the server and the whole request header has already been read.
然后采用ab测试工具,运行如下命令
ab -n 2 -c 2 http://127.0.0.1:8000/data.php
504
当出现504的时候也伴随着一段英文,504 Gateway Time-out
,顾名思义,就是超时了,复现这个错误码也很简单。让你的php程序模拟耗时请求,比如把php脚本里添加以下内容
php
sleep(70);//模拟耗时,睡70秒
echo "睡醒了";
重定向和缓存
301和302
之所以将这两个状态码放到一起,因为他们都是重定向,其中,301永久重定向
,302暂时重定向
。不管是暂时还是临时,对用户而言,这两者没什么区别,都是在访问A网站的时候跳转到了B网站,并看到浏览器上的地址栏变成了B网站的地址。有区别的是搜索引擎,搜索引擎是要建立索引规则和权重的,如果网站A被设定为永久重定向到B,那搜索引擎可以确定A的地址永久改变了,就会把B当做唯一有效的目标地址,这是搜索引擎会把老地址的PageRank等信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。所以,所以只要网站不是临时性迁移,都会做301重定向。
在nginx的rewrite语法中有两个关键字 permanent——永久重定向
redirect——临时重定向
如果我们想要将.asp文件永久重定向到index页面
location ~ \.asp$ {
rewrite ^(.*)$ /index.html permanent;
}
location ~ \.asp$ {
rewrite ^(.*)$ /index.html redirect;
}
再次访问页面是可以看到302冲重定向了,同样,浏览器地址栏上的地址变成了重定向后的地址
304
304 Not Modified
,默认情况下,nginx会对静态文件进行缓存。为了节省网络宽带,nginx和浏览器会产生如下交互
1. 浏览器客户端想请求一个文档,如果浏览器本地已经有缓存了,发送If-Modified-Since给Web服务器
2. 服务器将文件最后修改时间将服务器的文档修改时间Last-Modified和浏览器发送过来的If-Modified-Since比较,如果两者一致,返回304给浏览器,告诉浏览器用本地缓存就好了,如果两者不一致,返回200给浏览器,告诉浏览器使用最新的文档
在默认情况下,在浏览器中输入http://localhost:8000/test.css
请求css文件两次就会出现304
如果在服务器端编辑test.css
文件,由于这个时间文件最后修改时间发生了变更,这时服务器不会返回304状态码了。这时返回200状态码,两个的时间不一样了,浏览器采用最新的。
有关于各种缓存策略这里不做讨论。