由Content-Length致使的问题引起的一系列思考数据库
文章地址: blog.piaoruiqing.com/2019/09/08/…markdown
前段时间开发API网关, 使用postman调试时出现了超时的状况, 经排查肯定是请求数据被处理后
Content-Length
与实际不一致致使的问题, 故有此文.框架
Content-Length
, HTTP消息长度, 用十进制数字表示的八位字节的数目. 通常状况下, 不少工做都被框架完成, 咱们不多去关注这部份内容, 但少数状况下发生了Content-Length
与实际消息长度不一致, 程序可能会发生比较奇怪的异常, 如:分布式
Content-Length
是HTTP消息长度, 用十进制数字表示的八位字节的数目, 是Headers中常见的一个字段. Content-Length
应该是精确的, 不然就会致使异常 (特别地, HTTP1.0中这个字段无关紧要).oop
Content-Length
首部指示出报文中实体主体的字节大小. 这个大小是包含了全部内容编码的, 好比, 对文本文件进行了gzip
压缩的话, Content-Length
首部指的就是压缩后的大小而不是原始大小.post
Content-Length
使用十进制的数字表示了消息的长度, 服务端/客户端经过它来得知后续要读取消息的长度.ui
若是这个长度不正确, 会发生以下状况:编码
若是Content-Length比实际的长度大, 服务端/客户端读取到消息结尾后, 会等待下一个字节, 天然会无响应直到超时.spa
一样地, 在响应消息中Content-Length
超过实际长度也是同样的效果:调试
若是这个长度小于实际长度, 首次请求的消息会被截取, 好比参数为param=piaoruiqing
, Content-Length
为10, 那么此次请求的消息会被截取为: param=piao
, 如图所示:
但, 仅仅是如此吗, 固然不, 咱们再来看看第二次请求会发生什么让人意外的事情, 如图:
连续的两次请求, 第一次消息被截断, 而第二次没有发生预期的截断, 而是服务端抛出了异常: Request method 'ruiqingPOST' not supported
.刺不刺激 (ノ)゚Д゚( )
那 ruiqingPOST
是个什么神仙方法??? 此时, 凭着多年开发(DEBUG)经验练就的敏感度, 咱们大体能够猜出, 上一次请求被截取剩下的消息, 在此次请求出现了. 掏出wireshark来验证一下, 如图:
致使这种状况的缘由就是开启了Connection:keep-alive
, 若是使用Connection:close
, 所产生的现象就是每一次的请求都被截断, 但不会产生解析混乱(如将上一次剩下的消息拼接到后续的请求消息中).
Content-Length
首部指示出报文中实体主体的字节大小. 但如在请求处理完成前没法获取消息长度, 咱们就没法明确指定Content-Length
, 此时应该使用Transfer-Encoding: chunked
数据以一系列分块的形式进行发送. Content-Length
首部在这种状况下不被发送. 在每个分块的开头须要添加当前分块的长度, 以十六进制的形式表示,后面紧跟着 \r\n
, 以后是分块自己, 后面也是\r\n
. 终止块是一个常规的分块, 不一样之处在于其长度为0.
接下来咱们用一个下载文件的例子🌰, 来探讨Transfer-Encoding: chunked
是如何工做的. 服务端代码以下:
使用postman发起请求, wireshark抓包查看, 如图:
在wireshark中能够很清晰地看到chunked的数据, 其结构大体是: 返回的消息被分为多个数据块, 每一个数据块有两部分, 长度
+ 数据
, 这两部分都以CRLF(即\r\n
)结尾. 而终止块是一个特殊的数据块, 其长度为0, 如图:
如此, 即完成了分块编码. 其主要应用于以下场景, 即要传输大量的数据, 可是在请求在没有被处理完以前响应的长度是没法得到的. 例如, 当须要用从数据库中查询得到的数据生成一个大的HTML表格、须要传输大量的图片等.
Content-Length
若是存在且生效, 必须是正确的, 不然会发生异常.(大于实际值会超时, 小于实际值会截断并可能致使后续的数据解析混乱)Transfer-Encoding: chunked
首部, 那么Content-Length
将被忽略.若是这篇文章对您有帮助,请点个赞吧 ( ̄▽ ̄)"
欢迎关注公众号(代码如诗):