http status 400 – bad request_HTTP(13):誓言不过是一种异步操作

598920ab734c0f2233341de8c4fdafab.png

6.5 HTTP 状态码

HTTP 状态码(Status Codes)指的是 HTTP Response 报文中的状态码,它位于 Response 报文的 status-line:

status-line = HTTP-version SP status-code SP reason-phrase CRLF

比如:

HTTP/1.1 200 OK

关于状态码的基本概述,“6.1.2.2 start-line”已经做了描述,为了您的阅读方便,这里再粘帖一下:

status-code 标识 HTTP Server(也可能是 HTTP 中介)对 HTTP Client 的请求(Request)的响应结果,由3位数字组成。最著名的 status-code 也许就是“404”:所请求的页面不存在或已被删除(RFC 7231 对 404 的官方定义是 Not Found:The 404 (Not Found) status code indicates that the origin server did not find a current representation for the target resource or is not willing to disclose that one exists.)。

4792a7d98438037c78456fd8a13bcff4.png

status-code 的 ABNF 语法格式为:

status-code    = 3DIGIT

其中,DIGIT 代表十进制的数字0~9,3代表有3个 DIGIT。

status-code 的3位数字中的第1位,代表 status-code 的类别,其余两位数字代表更详细的含义。比如以4开头的 status-code 4xx 代表客户端错误(Client Error):4xx (Client Error): The request contains bad syntax or cannot be fulfilled,而更具体的 404 代表 Not Found,414 代表request-target 太长,服务器无法解释(The 414 (URI Too Long) status code indicates that the server is refusing to service the request because the request-target is longer than the server is willing to interpret)。

HTTP/1.1 一共定义了5类 status-code,分别是:

1xx:信息,服务器收到请求,需要请求者继续执行操作(Informational: The request was received, continuing process)

2xx 成功,操作被成功接收并处理(Successful: The request was successfully received,understood, and accepted)

3xx 重定向,需要进一步的操作以完成请求(Redirection: Further action needs to be taken in order to complete the request)

4xx 客户端错误,请求包含语法错误或无法完成请求(Client Error: The request contains bad syntax or cannot be fulfilled)

5xx 服务器错误,服务器在处理请求的过程中发生了错误(Server Error: The server failed to fulfill an apparently valid request)

状态码是可扩展的,只要得到批准,谁都可以到 IANA 上注册状态码。最新最全的已经注册的状态码,可以到 http://www.iana.org/assignments/http-status-codes 上查询。

HTTP Client 可以不理解所有的状态码,但是它必须理解所有的状态码类别(1~5)。对于不认识的状态码,HTTP Client 须将其当作x00,比如它不认识 404,但是须将其当作400来理解。

下面我们分别讲述每一类的状态码。

6.5.1 信息类 1xx(Informational)

1xx 类的状态码,所表达的是中间状态的信息。这里的中间状态,指的是“HTTP 业务”层面的中间状态。单纯从 HTTP 的“一问一答”的视角来说,HTTP Client 发送1个 Request 报文,然后收到1个 HTTP Server 的 Response 报文,这个 Request-Response 交互就结束了,没有什么中间状态。但是从 HTTP 业务层面来说,它可能需要多次 Request-Response 交互,才能完成 HTTP 的业务。

这么说实在有点抽象,而且还引入了一个新名词“HTTP 业务”,我们还是看具体的例子吧。“6.3.3.4 控制字段(Controls)”描述了这样的 Request 报文:

PUT /somewhere/fun HTTP/1.1

Content-Type: video/h264

Content-Length: 1234567890987

Expect: 100-continue

这个例子中的“Expect: 100-continue”字段的含义就是:我期望上传一个 video/h264 的数据,它的大小是 1234567890987 字节,期望你能同意。

对于这样的期望,如果 HTTP Server 同意,那么它的 Response 报文中的状态码就应该是100(Continue)。HTTP Client 收到了100状态码,就会在下一次 Request 报文中将该视频的真正数据(1234567890987字节)发送给 HTTP Server,然后 HTTP Server 再 Response。

上面的两次 Request-Response 往返,我们称之为1个 HTTP 业务。同时,第1次的 Response 的状态码,称为中间状态。

1xx 类状态码,包含两个具体的状态码:100、101。

100 (Continue)状态码就是 Request 报文中的“Expect: 100-continue”字段严格对应的。如果 Request 报文没有包含“Expect: 100-continue”字段,那么 HTTP Client 收到100状态码的 Response 报文时,它应该简单丢弃该 Response 报文(不须再做其他额外处理)。

101 (Switching Protocols)状态码指的是 HTTP Server 理解 HTTP Client 的请求,但是期望与 HTTP Client 能够升级其 HTTP 版本,然后双方再 HTTP 通信。由于当前普遍采用 HTTP/1.1 版本,这个状态码我们就不再介绍。

6.5.2 成功类 2xx(Successful)

没有什么比收到 2xx 状态码更让 HTTP Client 高兴的事了,它表明 HTTP Client 的 Request,被 HTTP Server 成功地接收、理解和接受:

我寄愁心与明月

明月皎皎照我床

但是,高兴归高兴,细细一体会,好像哪里不对,但是又说不上来。如果跟你的女神表白,女神回你两个字:收到!或者是另外两个字:理解

这到底是几个意思?女神到底有没有接受你的表白啊?

接收、理解、接受,这3个不同的词,可能会让你彻夜不眠,也可能会让 HTTP Client 辗转反侧(The 2xx (Successful) class of status code indicates that the client's request was successfully received, understood, and accepted, RFC 7231)。

这么说可能有点煽情,其实这只不过是涉及到同步操作和异步操作两个概念而已,如图6-66所示:

d266b8556e8b9daae44d1ee2737f68a8.png

图6-66 同步操作和异步操作

图6-66中,同步操作是 HTTP Server 收到 HTTP Client 的 Request 后,会先进行相关处理,并且处理成功后,再发送 Response 报文。HTTP Client 收到 Response 报文,它是明确知道 HTTP Server 已经处理成功。而异步操作则不然,HTTP Server 收到 HTTP Client 的 Request 后,它首先是回应 Response 报文,然后再做相应处理。需要说明的是,HTTP Server 并不确定 Response 以后何时开始处理,可能是立刻就处理,也可能是很长时间以后。而且,HTTP Server 也不能保证处理成功。所以,对于异步操作,HTTP Client 收到 Response 报文,它是无法 HTTP Server 的处理结果,甚至连 HTTP Server 是否已经开始处理也不知道。

HTTP Client 是如何知道它的请求在 HTTP Server 端是被同步处理还是异步处理呢?答案就是状态码。在成功类 2xx 的状态码中,目前只有202状态码表示异步操作,其余的都是同步操作。

下面我们就来看看成功类 2xx 中各个具体状态码的含义。

6.5.2.1 状态码:200、201、204、206

对于从事 web 编程的童鞋来说,他最常见的状态码应该不是404(Not Found),而是200(OK)。

d727c02455bc6d84c182409e29f0ce2b.png

除了表示异步的状态码202,200可以替代其他所有 2xx 状态码。这也意味着,(到目前为止)2xx 系列的状态码,除了202,其余都表示同步操作、并且操作成功了。但是除了“同步、成功”这两个关键词外,还有其他额外的细节信息需要表达,这是其他状态码存在的意义和独特价值。

200(OK)就是表达“同步、成功”,除了 CONNECT 请求所对应的响应,其他请求的 Response 报文都包含 Message Body,哪怕 Message Body 的长度等于0。

对于 PUT 和 POST 来说,它们的操作结果可能是修改(Update),也可能是创建(Create),该如何区分这两种操作结果呢?此时,200就无法胜任,得需要201出场。

201(Created)表达的含义是“同步、创建成功”。既然是创建成功,那么新创建资源的 URI 该是什么呢?有两种表达方式:

(1)或者就是 Request 报文中的 URI

(2)或者是另外的 URI,此时需要通过 Response 报文中的 Location 字段来表达。Location 字段的值,就是新创建资源的 URI。

200(OK)总是要求 Response 报文中包含 Message Body(除了回应 CONNECT 请求),但是有很多场景是不需要 Message Body 的,如图6-67所示:

04c049a04c7b6e072e00f0142d056a6c.png

图6-67 微信公众号素材编辑器

图6-67是一个微信公众号素材编辑器(可以简单理解为 Web 文档编辑器),当你敲入一段文字然后点击“保存”按钮时,服务端显然没有必要将你编辑的内容再回送给你,所以此时它的 Response 报文的状态码就可以是204(No Content),明确表示报文中不包含内容(Content),也就是不包含 Message Body。(说明:本文只是以微信做一个示意性的举例,不代表微信就是如此实现的)

有的场景不需要发送 Message Body,有的场景则需要发送所请求资源的部分信息。Range Retrieve(范围查询)的 Response 报文,就是发送资源的部分信息。与之对应的状态码就是206(Partial Content)。

Range Retrieve 的 Request 报文的报文头中应该包含 Range 等字段,Response 报文中应该包含 Content-Range 等字段,具体请参见“6.3.5 Range Retrieve”。

6.5.2.2 状态码:204、205

前文已经说过204(No Content),从节约带宽和提升效率的角度来说,204(No Content)有其必要性和独特价值。当 HTTP Client 收到204的 Response 报文时,它可以保持当前页面不变。一个 Web 文档编辑器,你点了保存之后,完全可以继续编辑,该编辑器不会做任何改变(比如跳转到其它页面),也不应该做任何改变。

但是,应该也好,不应该也罢,这已经不是 HTTP 的范畴,而是应用程序自己的决定。有的编辑器,当你点击保存之后,它就跳转到一个广告页面,让你看3秒钟广告后才能继续编辑,这是人家编辑器自己的事情,与 HTTP 无关。

从这个角度讲,205(Reset Content),有点不那么好理解,如图6-68所示:

6052905c06c603696ba33b87b6bfe2d5.png

 图6-68 Form 的3个状态

图6-68表达了一个 Form 的3个状态:

(A)初始化状态,比如第1次弹出该 Form

(B)用户编辑状态

(C)用户编辑提交以后的状态

抛开 HTTP,就是单纯从应用程序的易用性角度,C 状态的 Form 也应该将用户所编辑的内容清除,将该 Form 重置(Reset)为初始化状态。

但是,还是那句话,是不是重置,那是应用程序自己的事,与 HTTP 无关。所以,此时单纯看状态码205的表面含义“Reset Content(重置内容)”,那是有点莫名奇妙的,HTTP 是不是操了太多的心了?

唉,这个世界充满了太多的误解。如果一定要理解205(Reset Content)的话,还得看 RFC 7231 的一段文字:

The 205 (Reset Content) status code indicates that the server has fulfilled the request and desires that the user agent reset the "document view", which caused the request to be sent, to its original state as received from the origin server.

205(Reset Content)是让 User Agent 再到 HTTP Server 查询一遍,使用所查询到的值,去重置 User Agent 相关的“document view”。

原来重置的数据不在 HTTP Client,而在 HTTP Server。所以 HTTP Server 需要通过状态码205去通知 HTTP Client:来查询一下所需要的重置的值。

6.5.2.3 状态码:203、214

203(Non-Authoritative Information)的直译是“非权威信息”,这个怎么理解呢,请看图6-69:

7d002560413f0f95ca5f2d6c532e63b3.png

 图6-69 Non-Authoritative Information 示意

原来是 HTTP Proxy 将 HTTP Server 的响应报文做了修改,它得通过状态码203通知 HTTP Client:Response 报文被修改了。

有的资料说,状态码203所对应的修改,仅仅是 Response 的报文头,这是不准确的。首先,RFC 7231 没有明确说明只修改报文头:The 203 (Non-Authoritative Information) status code indicates that the request was successful but the enclosed payload has been modified

另外,设想一下,如果修改了报文头的 media-type 字段,那么 Response 报文的 Message Body 不修改几乎是不可能的。

203(Non-Authoritative Information)与214(Transformation Applied)非常相似,两者都是对 HTTP Server 的 Response 报文被修改以后的通知和告警。两者的不同点是:

(1)203(Non-Authoritative Information)所对应的原始 HTTP Server 的状态码是200。也就是说,HTTP Proxy 看到200以后才会修改,才会发送203状态码。

(2)214(Transformation Applied)则要广泛的多,无论原始 HTTP Server 的状态码是何值,HTTP Proxy 都可以修改原始 Response 报文,同时发送214状态码。

6.5.2.4 状态码:202

202(Accepted)是一个“异步操作”,它只是表明 HTTP Server 接受了 HTTP Client 的请求,但是何时处理这个请求,以及这个请求能否被处理成功,这都是 HTTP Server 不予保证的。这跟去面试,人家让你回去等通知,是差不多一个意思。

需要说明的是,Accepted(接受)在不同的语境下,其含义是不一样的。在 HTTP 里,202(Accepted)就是一个异步操作,对操作结果没有任何承诺。而女方如果接受了男方的求婚,那就是同步操作,那就表明的请求操作成功了。

但是,如果把求婚看作婚姻的第一步,那么求婚也是一个异步操作,没有人承诺接受求婚就意味着婚姻的天长地久,虽然

他(她)们都许下了誓言!

-------------------

7fea29bba409984061f9382bbc81db89.png

京东有售

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值