HTTP 中的状态码
状态码,从字面意思可以看出是描述状态的代码。一般呢就是由3位数字组成的,
比较官方的解释就是:“用以表示网页服务器超文本传输协议响应状态的3位数字代码”,
其实关于状态码,在实际场景中是很常见的,比如打开了一个不存在的页面,弹出404Not Found;或者由于服务器的问题,返回503
▶ 为什么要了解状态码?
1、实际场景中,可能会遇到这种情况,比如你测试调用某个接口,结果返回500(这里是做假设),然后你以为你的代码写错了,不断找错,最后可能发现是服务器的错(比如没有开启某个端口)。但如果你要是看了我的文章,知道5XX是描述服务器错误的状态码,那你就可以不用花那么多时间纠错。
2、或许你没遇到过上面的情况,但是面试官可能会问你有关状态码的问题,比如
- 说一下HTTP协议中503的状态?
- 302和301状态码的区别?
- HTTP中的XXX状态码代表着什么?
因此,了解状态码可以帮助我们在开发时,减少一些不必要的麻烦,或者可以避免我们在面试中因为不了解状态码而不知所言,废话不多说,进入正题。
正题
▶ 状态码的类别
我们先根据状态码的第一位数字进行分类,有以下5种类别:
||||
|---|---|---| | |类别|原因短语| |1XX|Informational(信息性状态码)|接收的请求正在处理| |2XX|Success(成功状态码)|请求正常处理完毕| |3XX|Redirection(重定向状态码)|需要进行附加操作以完成请求| |4XX|Client Error(客户端错误状态码)|服务器无法处理请求| |5XX|Server Error(服务端错误状态码)|服务器处理请求出错|
(其中1XX状态码不是很常见,这里不做描述)
▶ 状态码——200(OK)
显然,这是一个很常看到的状态码,一般我们只要能够正常访问网页,都会返回200
比如我们随便在谷歌搜索一个关键词,然后查看F12中的网络状态
可以发现,返回200状态码的响应报文所占比例还是挺大的
这里的200,就是用来告知我们(客户端)的请求被对方(服务端)正常处理啦,并且会根据请求方法的不同,判断是否返回资源
(比如使用GET请求时,对方(服务端)会将资源实体返回给我们(客户端);使用HEAD请求时,则不返回资源实体)
个人认为,200是最常见的状态码(毕竟一般我们都是正常访问的),也是最容易理解的状态码
▶ 状态码——204(Not Content)
204状态码跟200有点类似,都是代表我们(客户端)的请求被对方(服务端)正常处理
区别在于对方(服务端)不会返回也不允许返回任何资源实体
还是以谷歌搜索为例,仔细发现,上图中除了大部分的200状态码,还有小部分的204状态码
点击204状态码的响应报文,可以发现并没有返回资源实体
204状态码使用场景:
一般在只需要从客户端往服务端发送信息,而对客户端不需要发送新信息内容的情况下使用
▶ 状态码——206(Partial Content)
"Partial"的意思就是“部分的,局部的”,从字面意思上可以理解为返回部分内容
比较官方的解释:
表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含由Content-Range指定范围的实体内容
例子说明:
我们代表左边(客户端),对方代表右边(服务器)
假设我们(客户端)要请求某个学习资料.avi的后半部分(30001-60000),我们会说:
GET /xxxxx/xxx.avi HTTP/1.1
Host: xxx.xx
Range: bytes=30001-60000
对方(服务器)听到之后,意识到你只需要xxx.avi中30001-60000范围的部分,
给你回信,信中说道:
HTTP/1.1 206 Partial Content
Content-Length: 30000
Content-Range: bytes 30001-60000
Content-Type: video/mpeg
这时候,对方回信的内容会附带206 Partial Content状态码以及Content-Range: bytes 30001-60000资源范围
206状态码使用场景:
一般用于资源范围请求,如果我们只需要部分的资源,则对方会返回206状态码来说明成功返回部分资源
(特殊情况:如果对方无法处理该服务请求时,则会返回200状态码以及全部资源)
▶ 2XX状态码小结:
综上,我们可以明白2XX的响应结果表明请求被对方正常处理了
▶ 状态码——301(Moved Permanently)
"Moved Permanently"在有道翻译的解释为:
● 永久移动
● 客户试图访问的资源已移到新的永久位置
● 永久移除
比较官方的解释:
永久性重定向(重定向就是从某个URI跳转到新的URI)
该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的URI
(新的URI会在响应首部Location字段出现)
例子说明:
我在使用谷歌搜索时,会直接在浏览器中输入http://google.com,这时候如果观察F12中网络的变化,你会发现有一条返回301的响应信息
点击查看具体信息
图中标红的地址就是我们在地址栏中输入的地址
标蓝的地址就是对方告诉我们应该访问新的地址http://www.google.com/
这时候,浏览器接收到服务器返回的301状态码后,就会根据响应首部location字段的新地址(这里就是http://www.google.com)进行重新请求
301状态码的使用场景:
● 域名跳转,比如上述例子,将google.com跳转到www.google.com
● 旧URI已经失效,需要通知用户访问新URI,这时候可以使用301永久重定向,通知用户使用location字段的新地址进行访问
▶ 状态码——302(Moved Temporarily)
"Moved Temporarily"在有道翻译的解释为:
● 临时移动
比较官方的解释:
临时性重定向
该状态码表示请求的资源已被分配了新的URI,希望用户(本次)能使用新的URI访问
302跟301比较类似,但注意301是永久性重定向,302是临时性重定向,什么意思呢?
在上面301的使用场景中,我们提到第二个场景,这时候的旧URI已经失效,用户无法继续访问,而302的场景跟301相反
旧URI还是可以使用,旧URI的资源只是临时被移动到新的URI中
例子说明:
淘宝大家都使用过吧,假如我登录账号查看我的淘宝购物车,我们先保存购物车中对应的URI
https://buyertrade.taobao.com/trade/itemlist/list_bought_items.htm?spm=a21bo.2017.1997525045.2.5af911d9xpHb6l
接下来在别的浏览器中打开上面的URI,同时打开F12观察网络状况
服务器返回302状态给我们了,这是因为这个URI原本应该是打开购物车的,但是由于我们在别的浏览器打开,没有登录信息
打开该条响应信息
会在location首部字段中返回新的URI,通知浏览器临时跳转到新的URI中,即登录页面的URI,告知我们需要登录才可以查看购物车
302状态码的使用场景:
综上所述,我们可以推出302状态码可以应用在网页登录信息失效时临时跳转到新的URI
又或者,网站中有临时的页面需要跳转,而原来的页面需要保留时,可以返回302状态码以起临时重定向的作用
▶ 状态码——303(See Other)
比较官方的解释:
该状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源
303跟302相比,其实功能都是一样的,都是起到临时重定向的作用,
唯一的区别是303状态码明确表示客户端应当采用GET方法获取资源。
303状态码的使用场景:
跟302一样,只是这里希望我们使用GET方法来获取资源
小Tips:
当301、302、303响应状态码返回时,几乎所有浏览器都会把POST改成GET,并删除请求报文内的主题,之后请求会自动再次发送。
301、302的标准中是禁止将POST方法改变成GET方法的,但实际使用时大家都会这么做。
▶ 状态码——304(Not Modified)
"Not Modified"
● 未修改
比较官方的解释:
该状态码表示客户端发送附带条件的请求(指GET方法请求报文中包含If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since中任一首部)时,服务端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304 Not Modified(服务器端资源未改变,可直接使用客户端未过期的缓存)。
例子说明:
现在有个场景,我们第一次打开淘宝时,观察到标红区域是返回200状态码的
按下F5刷新一下淘宝
观察一下标红区域返回的状态码,从200变成了304
按下Ctrl+F5再次刷新淘宝
观察到该状态码又变成了200
(这里的Ctrl+F5是强制刷新,会清理缓存,而F5只是将当前页面进行刷新,不会清理缓存)
为什么会第二次刷新时会变成304呢?我们从第一次打开淘宝说起
第一次打开淘宝时,search-suggest-history-iframe会返回一个Etag标志给我们,Etag的值为W/"2aba-1602480f459",同时返回200状态码(ETag是用来标识服务器中的每份资源,假设用001来标识资源A,用032来标识资源B)
我们观察到服务器返回一个Cache-Control字段,该字段让我们进行对search-suggest-history-iframe缓存60s(标蓝字段)
第二次打开淘宝时,我们客户端会自动发送一个If-None-Match字段,这个字段的值就是Etag的值W/"2aba-1602480f459"
服务器接收到第二次请求时,发现我们给了它一个If-None-Match参数,然后将参数中的值,也就是W/"2aba-1602480f459"
跟服务器中的ETag进行对比,如果相同,则返回304状态码,表示服务器的资源未修改,让我们继续使用本地缓存
如果If-None-Match的值跟ETag的值不相等,则会返回200状态码,表示服务器的资源已经修改,这时候会返回新的资源给我们
类比生活场景:
304状态码可能会比较难理解,因为涉及到缓存以及ETag等知识点,如果实在不是很理解ETag,
那我们可以把它当作现实世界中的门牌,服务器就是一家酒店,
我们(客户)需要去某个房间时,首先到前台咨询是否有我们想要的房间(发送请求),
前台告诉我们空房间门牌号为101并给我们101门卡(ETag),这时我们就可以去房间了(访问资源)。
我们把行李搬进房间后去外面吃饭,这时候再回来酒店的话(第二次访问),我们可以直接通过门卡(If-None-Match的值)去房间,而不用再去咨询前台了(相当于做了缓存)
当然,实际情况可能会更加复杂,这里只是做一个简单的类比,方便大家理解。
304状态码的使用场景:
对一些频繁访问的静态文件,比如html、css、js等,可以使用304做缓存,从而减少服务器的负担,提升网站访问速度
▶ 状态码——307(Temporary Redirect)
"Temporary Redirect"
● 临时重定向
比较官方的解释:
临时性重定向
该状态码与302有着相同的含义。尽管302标准禁止POST变换成GET,但实际使用时大家并不遵守
307会遵照浏览器标准,不会从POST变成GET,但不同的浏览器可能会出现不同的情况
307状态码的使用场景:
跟302一样,只是会要求我们使用POST方法来重定向Location字段的URI
▶ 3XX状态码小结:
综上,其实除了304状态码跟重定向没什么关系,其余的状态码都跟重定向相关
▶ 状态码——400(Bad Request)
“Bad Request”
● 请求错误
比较官方的解释:
该状态码表示请求报文中存在语法错误。
这个很好理解,一般发生400错误的话,建议检查一下请求的内容再次发送请求,
其次,浏览器会像200状态码一样对待该状态码。
例子说明:
▶ 状态码——401(Unauthorized)
“Unauthorized”
● 非法的
● 未被授权的
比较官方的解释:
该状态码表示发送的请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息。
例子说明:
以BASIC认证作为例子
我们直接访问http://xxx.xx/login.html时,服务器返回401,并携带WWW-Authenticate首部字段询问用户信息
这时候会弹出登录窗口,提示我们输入用户名和密码,这里假设用户名为user,密码为123
用户和密码中间用分号:隔开,再经过Base64方式编码(user:123 → dXNlciUzQTEyMw==)
将编码后的字符串写入请求首部字段Authorization中并发送给服务器
若认证成功,则返回200;若认证失败,则还是返回401
401状态码的使用场景:
使用HTTP认证时,可以通过401寻求用户的登录情况或者返回用户信息是否认证成功
▶ 状态码——403(Forbidden)
“Forbidden”
● 被禁止的
● 严禁的
比较官方的解释:
该状态码表明对请求资源的访问被服务器拒绝了
403状态码的例子就不再赘述,大家可以直接看它的使用场景,也是挺好理解的
403状态码的使用场景:
● IP被服务器拉黑
● 身份认证时密码出错
● 访问目录的权限不够
● 等等等等
▶ 状态码——404(Not Found)
"Not Found"
● 未找到
比较官方的解释:
该状态码表明服务器上无法找到请求的资源。
例子说明:
这个还是比较常见的吧,我们打开某个网站,结果弹出404,告诉我们找不到这个网址
比如下方的https://www.google.com/xxx.xx
现在国内一些网站在弹出404时,会顺带一张寻人启事,例如打开https://www.qq.com/xxx.xx
404状态码的使用场景:
客户端输入一个不存在的URI,服务端返回404
▶ 4XX状态码小结:
综上,我们可以找到一个规律,那就是返回4XX的状态码一般都是我们客户端出现错误的原因
比如请求语法错误(400)、需要认证(401)、权限不够(403)、输入错误URI(404)
▶ 状态码——500(Internal Server Error)
"Internal Server Error"
● 内部服务器错误
这个情况我遇到过,因为返回500找了好久的错,最终记录在下面这篇博客中,感兴趣的可以看看
【PHP】在阿里云服务器Ubuntu邮箱PHPMailer使用出现500的问题
比较官方的解释:
该状态码表明服务器端在执行请求时发生了错误,也有可能是Web应用存在的bug或某些临时的故障
例子说明:
有这么一个场景,我们需要实现一个自动发送邮箱的功能,该功能需要配合SMTP(简单邮件传送协议,Simple Mail Transfer Protocol)
这时我们的代码是完全没问题的,可就是一直发送不了邮箱,一直返回500状态码
最后发现是因为服务器没有开启25端口(SMTP的默认端口是25),导致SMTP服务无法正常进行
返回500状态码是由于服务器内部发生错误了,那什么时候会返回500呢
500状态码的使用场景:
● 服务端代码出错(包括后端代码,比如PHP、Java;数据库代码等)
● 未开放指定端口
▶ 状态码——503(Service Unavailable)
"Service Unavailable"
● 服务不可用
● 无法提供服务
比较官方的解释:
该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
例子说明:
这个情况也比较常见,比如抢课时服务器崩溃,如下图,有大量的用户同时请求,服务器承载不住了
503状态码的使用场景:
● 服务器超载
● 服务器停机维护
▶ 5XX状态码小结:
这个跟4XX的错误是相反的,4XX是由于客户端错误引起的,而5XX是服务器本身发生错误引起的