楔子
我们已经学习了 HTTP 报文里请求行的组成部分,包括请求方法和 URI。有了请求行,加上后面的头字段就形成了请求头,可以通过 TCP/IP 协议发送给服务器。服务器收到请求报文,解析后需要进行处理,具体的业务逻辑多种多样,但最后必定是拼出一个响应报文发回客户端。响应报文由响应头加响应体数据组成,响应头又由状态行和头字段构成。而我们说状态行有三部分:
开头的 Version 部分是 HTTP 协议的版本号,通常是 HTTP/1.1,用处不是很大。后面的 Reason 部分是原因短语,是状态码的简短文字描述,例如 OK、Not Found 等等,也可以自定义。但它只是为了兼容早期的文本客户端而存在,提供的信息很有限,目前的大多数客户端都会忽略它。所以,状态行里有用的就只剩下中间的状态码(Status Code)了。它是一个十进制数字,以代码的形式表示服务器对请求的处理结果,就像我们通常编写程序时函数返回的错误码一样。
不过你要注意,它的名字是状态码、而不是错误码。也就是说,它的含义不仅是错误,更重要的意义在于表达 HTTP 数据处理的状态,客户端可以依据代码适时转换处理状态,例如继续发送请求、切换协议,重定向跳转等,有那么点 TCP 状态转换的意思。
状态码
目前 RFC 标准里规定的状态码是三位数,所以取值范围就是从 000 到 999。但如果把代码简单地从 000 开始顺序编下去就显得有点太 low,不灵活、不利于扩展,所以状态码也被设计成有一定的格式。RFC 标准把状态码分成了五类,用数字的第一位表示分类,而 0~99 不用,这样状态码的实际可用范围就大大缩小了,由 000~999 变成了 100~599。这五类的具体含义是:
1xx
1xx 类状态码属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
2xx
2xx 类状态码表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
「200 OK」是最常见的成功状态码,表示一切正常。如果是非 HEAD 请求,服务器返回的响应头都会有 body 数据
「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据
「206 Partial Content」是应用于 HTTP 分块下载或断电续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态
3xx
3xx 类状态码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问
「302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问
「301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL
「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制
4xx
4xx 类状态码表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
「400 Bad Request」表示客户端请求的报文有错误,但只是个笼统的错误
「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错
「404 Not Found」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端
5xx
4xx 类状态码表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误码。
「500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道
「501 Not Implemented」表示客户端请求的功能还不支持,类似 "即将开业,敬请期待" 的意思
「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似 "网络服务正忙,请稍后重试" 的意思
在 HTTP 协议中,正确地理解并应用这些状态码不是客户端或服务器单方的责任,而是双方共同的责任。客户端作为请求的发起方,获取响应报文后,需要通过状态码知道请求是否被正确处理,是否要再次发送请求,如果出错了原因又是什么。这样才能进行下一步的动作,要么发送新请求,要么改正错误重发请求。服务器端作为请求的接收方,也应该很好地运用状态码。在处理请求时,选择最恰当的状态码回复客户端,告知客户端处理的结果,指示客户端下一步应该如何行动。特别是在出错的时候,尽量不要简单地返 400、500 这样意思含糊不清的状态码。