前段时间看了《御赐小仵作》,里面有很多细节很有心。看了一些评论都是:终于在剧里能够看到真正在搞事业、发了工资第一时间还钱的正常人了。我印象比较深的是王府才能吃上的葡萄。觉得非常合理。剧里说的明明白白,是唐朝中晚期唐宣宗的时候,那时候丝绸之路刚刚开通,西域(现在的新疆以及更西的地方)的葡萄终于能吃上了,这就和那一整段历史给对应上了。
谈到对应的问题,咱们回到正题,http状态码1XX。对于http状态200、404、500,大家可能熟悉一些。1XX可能实际中从来没有见过,今天咱们用剥洋葱的叙述方式,拨开1XX状态码的层层面纱。
定义
HTTP状态码(英语:HTTP Status Code)是用以表示网页服务器超文本传输协议响应状态的3位数字代码。这句话要注意解读了。我先来考考大家读懂了没。请回答:
这里我先不回答,无法决定的朋友再多读几遍定义。
状态码1XX表示服务端已经收到了请求,但是还需要进一步处理。
白居易有一首《问刘十九》:
绿蚁新醅酒,红泥小火炉。
晚来天欲雪,能饮一杯无?
这就和服务端可能会返回1XX的场景很像。客户端发起一个请求:我这里有美酒和暖炉,天要下雪了,来喝一杯?服务端收到之后返回1XX。代表接受邀请。这时候客户端就可以真正摆上一桌酒菜迎接客人了。如果服务端返回4XX,客户端也不用消耗资源杀鸡做菜了。
1xx状态码是 HTTP/1.1 版本新定义的,用来表示请求被正常接收,会进行进一步处理。这些状态码相对较新,并且 HTTP/1.0 版本无法识别,所以原则上不应该向HTTP/1.0版本的客户端发送任何1xx状态码。
100 Continue
该状态码说明服务器收到了请求的初始部分,并请客户端继续发送。在服务器发送了 100 Continue 状态码之后,如果收到客户端的请求,则必须进行响应。
这个状态码实际上是对如下场景的一种优化:客户端有一个较大的文件需要上传并保存,但是客户端不知道服务器是否愿意接受这个文件,所以希望在消耗网络资源进行传输之前,先询问一下服务器的意愿。实际操作为客户端发送一条特殊的请求报文,报文的头部应包含
Expect: 100-continue
此时,如果服务器愿意接受,就会返回 100 Continue 状态码,反之则返回 417 Expectation Failed 状态码。对于客户端而言,如果客户端没有发送实际请求的打算,则不应该发送包含 100 Continue Expect 的报文,因为这样会让服务器误以为客户端将要发送一个请求。大家可以基于对100的理解再回想一下《问刘十九》。
之前提到过,并不是所有的HTTP应用都支持 100 Continue 这个状态码(例如HTTP/1.0及之前的版本的代理或服务器)所以客户端不应该在发送 100 Continue Expect 后一直等待服务器的响应,在一定时间后,客户端应当直接发送计划发送的内容。
而对于服务器而言,也不应当把 100 Continue 当作一个严格的判断方法。服务器有可能在发送回应之前就收到了客户端发来的主体报文。此时服务器就不需要再发送 100 Continue 作为回应了。但仍然需要在接受完成后返回适当的状态码。理论上,当服务器收到一个 100 Continue Expect 请求时,应当进行响应。但服务器永远也不应向没有发送 100 Continue Expect 请求的客户端发送100 Continue 状态码作为回应。这里提到的应当进行响应是指:假设服务器不打算接收客户端将要发送的主体报文,也应当做适当的响应(例如发送 417 Expectation Failed)而不是单纯的关闭连接,这样会对客户端在网络层面上产生影响。
作为代理的HTTP应用在收到带有 100 Continue Expect 的请求时,需要进行额外的判断。假设代理服务器明确知道报文下游的HTTP版本是兼容 HTTP/1.1 的,或者代理服务器不知道报文下游的版本,它都应当转发这条 100 Continue Expect 请求。但是如果代理服务器明确知道报文下游的应用无法处理 100 Continue Expect 的话,则应当直接向客户端返回 417 Expectation Failed 作为响应。而这也并非唯一的解决办法,另一种可行的办法是直接向客户端返回 100 Continue ,然后向下游传递删除了 100 Continue Expect 的报文。
另外,如果代理服务器决定为 HTTP/1.0 及之前的版本服务的话,那么当它收到来自服务器的 100 Continue 响应报文时,则不应当向客户端转发这条响应,因为客户端很可能不知道如何处理该报文。
101 Switching Protocols
HTTP 101 Switching Protocol(协议切换)状态码表示服务器应客户端升级协议的请求对协议进行切换。
此机制始终由客户端发起,并且服务器可能接受或拒绝切换到新协议。客户端可使用常用的协议(如HTTP / 1.1)发起请求,请求说明需要切换到HTTP / 2或甚至到WebSocket。
我们来看一个实际的例子:
为了实现WebSocket通信,首先需要客户端发起一次普通HTTP请求。也就是说,WebSocket的建立是依赖HTTP的。
其中HTTP头部字段Upgrade: websocket和Connection: Upgrade非常重要,告诉服务器通信协议将发生改变,转为WebSocket协议。支持WebSocket的服务器端在确认以上请求后,应返回状态码为101 Switching Protocols的响应:
其中字段Sec-WebSocket-Accept是由服务器对前面客户端发送的Sec-WebSocket-Key进行确认和加密后的结果,相当于一次验证,以帮助客户端确信对方是真实可用的WebSocket服务器。
验证通过后,这个握手响应就确立了WebSocket连接,此后,服务器端就可以主动发信息给客户端了。此时的状态比较像服务器端和客户端接通了电话,无论是谁有什么信息想告诉对方,开口就好了。
一旦建立了WebSocket连接,此后的通信就不再使用HTTP了,改为使用WebSocket独立的数据帧。
102 Processing
102 Processing是由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。
Web服务器可能需要相当长的时间来处理复杂的请求。当客户端的浏览器发送包含多个涉及复杂需求的子请求的WebDAV请求时,服务器需要一些时间来处理并发送此代码“102–Processing”。此代码旨在通过通知客户端服务器收到请求并对其进行处理来避免客户端出现超时错误。
总结
HTTP状态码的设计规则是:前面一位是分类。2XX表示服务端已经收到了请求,并且已经分析处理完;3XX表示服务端已经收到了请求,但是还需要其他资源或者服务处理;4XX表示服务端已经收到了请求,但是无法理解,说明客户端请求姿势不正确;5XX表示服务端已经收到了请求,但是由于服务端自身问题无法正确响应。
这种编码方法在很多地方都在用。
比如身份证号规则前1、2位数字表示:所在省(直辖市、自治区)的代码;第3、4位数字表示:所在地级市(自治州)的代码;第5、6位数字表示:所在区(县、自治县、县级市)的代码;第7—14位数字表示:出生年、月、日;第15、16位数字表示:所在地的派出所的代码;第17位数字表示性别:奇数表示男性,偶数表示女性;第18位数字是校检码。
比如行别代码支付系统为每类参与者分配一个标识号,由三位数字组成,第一位是银行类型,剩下两位是标识号。
支付系统的参与者行号规则和身份证规则很像,除了每几位都有特殊含义,结尾一位也是验证码。反正参与者行号规则我是记下来了。默念了8遍记下来的,真不容易。