RFC2616--100状态码(规范与测试)

RFC2616中对100状态码的解释

100(continue)状态的目的是允许一个正在发送带有请求体的请求消息的客户端在发送请求体之前确定源服务是否愿意接受该请求(基于请求头)。在某些情况下,如果服务端拒绝查看请求体,而客户端继续发送请求体,这是不恰当的或者效率低下的。

对于HTTP/1.1客户端的规范:

  • 如果客户端在发送请求体之前愿意等待100(Continue)响应,那么它必须发送一个Expect请求头域,域值为100-continue

  • 如果客户端不打算发送请求体,它就不要发送一个值是”100-continue”的Expect请求头域

由于有老版本实现的存在,协议允许有这样一个不明确的情况:客户端在发送Expect:100-continue后,可能既收不到一个失败的状态码417,也收不到成功的状态码100(Continue)。因此,客户端向源服务端发送这样的头域而没有收到100响应时,在发送请求体之前,它不应该无限等待。

对于HTTP/1.1服务端的规范:

  • 当接收到带有Expect:100-continue请求头域的request后,服务端必须要么响应一个100状态并且从输入流中继续读取,要么响应一个最终状态码;在发送100响应之前,服务端不能等待读取请求体;如果服务端响应了一个最终的状态码,它可能会关闭传输连接或者继续读取并丢弃请求的剩余部分;如果它返回了一个最终的状态码,它就不能执行被请求的方法。

  • 如果请求消息不含值为”100-continue”的Expect请求头域,那么服务端不应该发送100响应;如果请求来自于HTTP/1.0或者更早的版本,服务端也不应该发送100响应;对于这个规则有个例外:为了兼容RFC2068,对于HTTP/1.1的PUT或者POST请求(头部没有带有Expect:100-continue),服务端也可能会发送100响应。这个例外的目的是为了最小化客户端处理未声明的等待100状态码造成的延迟,这只能应用于HTTP/1.1版本,不针对其他HTTP版本。

  • 如果服务端已经收到一些或者所有的相关请求的请求体,它可能会疏忽100响应

  • 发送了100响应的服务端必须在请求体一旦被接收和处理之后就发送一个最终状态码,除非它提前中止传输连接。

  • 服务端收到一个不带有Expect:100-continue请求头的request,这个请求包含一个请求体,如果服务端在从传输连接中读取完整个请求体之前,就已经响应了最终的状态码,这时服务端应该直到读取了整个请求或者直到客户端关闭连接才能关闭这个传输连接。否则,客户端可能会接收到不可靠的响应信息。然而,这个规定没有被解释为阻止了服务端保护自己不受服务式攻击和严重缺陷的客户端实现。

对于HTTP/1.1代理的规范:

  • 如果代理接收到一个带有Expect:100-continue请求头的request后,不管代理知不知道下一站服务端的HTTP版本是1.1还是更高版本,或者根本不知道,它都要传递请求,包括Expect头域。

  • 如果代理知道下一站服务端的HTTP版本是1.0或者更低,它不能转发请求并且要响应一个417错误码

  • 代理应该缓存记录最近访问的下一站服务端HTTP版本号

  • 如果代理接收到一个来自于HTTP/1.0的请求并且这个请求的头部没有包含Expect:100-continue,那么代理就不能转发100响应。这个规定优先于转发1XX响应码的通用规则

现在来测试一下

测试环境:

客户端:postman模拟http请求(客户端和服务端在同一局域网,并没有在同一主机上),IP:192.168.43.124
服务端:tomcat,IP:192.168.43.58
抓包工具:Wireshark

1.发送带有Expect:100-continue请求头域的post请求,且请求带有请求body(这里没有测试get带请求体,因为postman不让带)【get是可以带请求体的,只是不符合RFC规范而已】

前三帧就是三次tcp握爪了,第四帧是客户端发送的http请求,点开

这是一个完整的http请求,头部和实体都在,但看的出来头部和实体不是一起发送的。
第五帧,服务端响应100
第六帧,客户端确认收到100
第七帧,服务端收到完整的http请求,返回200响应和客户端请求的内容
第八帧,客户端确认收到信息

2.发送带有Expect:100-continue请求头域的post、get请求,且请求不带有请求body

不管是get还是post,当请求中不带有请求体时,只要头部中带有Expect:100-continue,都会收到100状态码,这虽然和上面RFC规范不符合(上面对于客户端的规范:如果客户端不打算发送请求体,它就不要发送一个值是”100-continue”的Expect请求头域),但仍然是可以这么做的。

所以,规范和具体的实现是不一样的。之前看到网上有人比较get与post的区别,说get只产生一个tcp包,而post产生两个,那篇文章说对于get请求,客户端会把头部和实体一起发出去,这是一个tcp包;而post请求,客户端会先把头发出去,等待100响应,然后再发实体,这是两个tcp包。为什么会这么说呢?当我用postman去测试的时候,发现get和post都产生了一个tcp包啊,后来加大了数据量,可以发现,无论是get还是post请求,都是要分包的,在postman下,将数据以1514byte为单位分包,例如:总长度为3614,那么就会分包为1514,1514,586,这种分包是从前往后切割,而不是分为头部和实体切割。

这里写图片描述

至于像那篇文章说的,要等待100响应,在postman上是没发现。后来我上网查了一下,可能他使用的是curl,网上说curl在post的数据超过1024k时,会分为两步(没有验证过):
1、发送一个请求,该请求头部包含一个Expect: 100-continue的字段,用来询问server是否愿意接受数据
2、当接收到从server返回的100-continue的应答后,它才会真正的发起POST请求,将数据发送给server。

现在已经验证了那个说法是错误的了,并不是在所有环境都适用,我们再接着讨论。既然我们上面已经用postman验证了,不管是get还是post,传输大数据时,将数据以1514byte为单位分包。我们能把这个当成结论或者理论来用吗?很明显是不能的,这只是在postman下这样,你能保证在其他工具或者浏览器里这个结论也行得通吗。那篇文章的作者就是把在某一工具下得出的结果当成一个对的理论来用了。把在某一工具下进行的不严谨的测试结果来当成get和post两者的区别显然是错误的,说白了就是把规范和具体实现弄混了,我们在比较post与get的区别时,肯定是从规范(specification)来比较,而不会是从具体实现(implementation)比较,毕竟一个规范可以有多种实现(可以严格遵守规范,也可以不遵守)【像RFC就是规范,而curl和postman就是具体实现】,当在一种实现里得出的正确结果可能在另一实现里就是错误的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值