http请求中的Content-Length作用机制与分块chunked

摘要:
httpclient-4.5.9.jarorg.apache.http:auth身份client端conn连接cookie本地impl:实现execchain异常httpcore-4.4.11.jarorg.apache.http.entity;AbstractHttpEntityhttp请求体包报文格式:Content-Type:报文类型:application/json;charset=utf

httpclient-4.5.9.jar

org.apache.http:

auth 身份

client 端

conn 连接

cookie 本地

impl: 实现

execchain 异常

httpcore-4.4.11.jar

org.apache.http.entity;

AbstractHttpEntity

http请求体包报文格式:

Content-Type: 报文类型:application/json;charset=utf-8

Content-Encoding: 编码方式:gzip或deflate

Content-Length: 报文长度:

Chunked: 是否分块传输

Content-Length, HTTP消息长度, 用十进制数字表示的八位字节的数目. 一般情况下, 很多工作都被框架完成, 我们很少去关注这部分内容, 但少数情况下发生了Content-Length与实际消息长度不一致, 程序可能会发生比较奇怪的异常, 如:

  • 无响应直到超时.
  • 请求被截断, 而且下一个请求解析出现错乱.

Content-Length是HTTP消息长度, 用十进制数字表示的八位字节的数目, 是Headers中常见的一个字段.Content-Length应该是精确的, 否则就会导致异常 (特别地, HTTP1.0中这个字段可有可无).

Content-Length首部指示出报文中实体主体的字节大小. 这个大小是包含了所有内容编码的, 比如, 对文本文件进行了gzip压缩的话,Content-Length首部指的就是压缩后的大小而不是原始大小.

Content-Length是如何工作的

Content-Length使用十进制的数字表示了消息的长度, 服务端/客户端通过它来得知后续要读取消息的长度.

http请求中的Content-Length作用机制与分块chunked第1张
image
http请求中的Content-Length作用机制与分块chunked第2张
image

如果这个长度不正确, 会发生如下情况:

Content-Length > 实际长度

如果Content-Length比实际的长度大, 服务端/客户端读取到消息结尾后, 会等待下一个字节, 自然会无响应直到超时.

http请求中的Content-Length作用机制与分块chunked第3张
image

同样地, 在响应消息中Content-Length超过实际长度也是一样的效果:

http请求中的Content-Length作用机制与分块chunked第4张
image
http请求中的Content-Length作用机制与分块chunked第5张
image

Content-Length < 实际长度

如果这个长度小于实际长度, 首次请求的消息会被截取, 比如参数为param=piaoruiqing,Content-Length为10, 那么这次请求的消息会被截取为:param=piao, 如图所示:

http请求中的Content-Length作用机制与分块chunked第6张
image
http请求中的Content-Length作用机制与分块chunked第7张
image

但, 仅仅是如此吗, 当然不, 我们再来看看第二次请求会发生什么让人意外的事情, 如图:

http请求中的Content-Length作用机制与分块chunked第8张
image

连续的两次请求, 第一次消息被截断, 而第二次没有发生预期的截断, 而是服务端抛出了异常:Request method 'ruiqingPOST' not supported.刺不刺激 (ノ)゚Д゚( )

ruiqingPOST是个什么神仙方法??? 此时, 凭着多年开发(DEBUG)经验练就的敏感度, 我们大致可以猜出, 上一次请求被截取剩下的消息, 在这次请求出现了. 掏出wireshark来验证一下, 如图:

http请求中的Content-Length作用机制与分块chunked第9张
image

导致这种情况的原因就是开启了Connection:keep-alive, 如果使用Connection:close, 所产生的现象就是每一次的请求都被截断, 但不会产生解析混乱(如将上一次剩下的消息拼接到后续的请求消息中).

不确定Content-Length的值怎么办

Content-Length首部指示出报文中实体主体的字节大小. 但如在请求处理完成前无法获取消息长度, 我们就无法明确指定Content-Length, 此时应该使用Transfer-Encoding: chunked

什么是Transfer-Encoding: chunked

数据以一系列分块的形式进行发送.Content-Length首部在这种情况下不被发送. 在每一个分块的开头需要添加当前分块的长度, 以十六进制的形式表示,后面紧跟着, 之后是分块本身, 后面也是. 终止块是一个常规的分块, 不同之处在于其长度为0.

Transfer-Encoding: chunked是如何工作的

接下来我们用一个下载文件的例子, 来探讨Transfer-Encoding: chunked是如何工作的. 服务端代码如下:

http请求中的Content-Length作用机制与分块chunked第10张
image

使用postman发起请求, wireshark抓包查看, 如图:

http请求中的Content-Length作用机制与分块chunked第11张
image

在wireshark中可以很清晰地看到chunked的数据, 其结构大致是: 返回的消息被分为多个数据块, 每个数据块有两部分,长度+数据, 这两部分都以CRLF(即)结尾. 而终止块是一个特殊的数据块, 其长度为0, 如图:

http请求中的Content-Length作用机制与分块chunked第12张
image

如此, 即完成了分块编码. 其主要应用于如下场景, 即要传输大量的数据, 但是在请求在没有被处理完之前响应的长度是无法获得的. 例如, 当需要用从数据库中查询获得的数据生成一个大的HTML表格、需要传输大量的图片等.

  • Content-Length如果存在且生效, 必须是正确的, 否则会发生异常.(大于实际值会超时, 小于实际值会截断并可能导致后续的数据解析混乱)
  • 如果报文中包含Transfer-Encoding: chunked首部, 那么Content-Length将被忽略.
  • @转自:https://blog.piaoruiqing.com.

免责声明:文章转载自《http请求中的Content-Length作用机制与分块chunked》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Node.JS + MongoDB技术浅谈CSS专题(三):页面高度发微下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

PHP $_SERVER 及用户真实IP

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些没有在这里列举出来的项目。 下表列出了所有 $_SERVER 变量中的重要元素。 元素/代码 描述 $...

Fiddler(一)

Fiddler:学习scrapy,不只是满足于网页上爬去信息的成功乐趣,现在开始接触爬去手机信息了,不好解决,知道过程不会轻松,但自己想去尝试。QAQ 写这篇博客是基于以下的几位大神学习笔记,我只是做下总结,里面会有具体的图片信息: https://blog.csdn.net/playstudy/article/details/18921967 https...

使用Guzzle执行HTTP请求

  Guzzle是一个PHP的HTTP客户端,用来轻而易举地发送请求,并集成到我们的WEB服务上。Guzzle提供了简单的接口,构建查询语句、POST请求、分流上传下载大文件、使用HTTP cookies、上传JSON数据等等。 安装 使用Composer安装: composer require guzzlehttp/guzzle 或者编辑项目的co...

Wireshark中TCP segment of a reassembled PDU的含义

By francis_haoSep 16,2017 在用Wireshark抓包的时候,经常会看到TCP segment of a reassembled PDU,字面意思是要重组的协议数据单元(PDU:Protocol Data Unit)的TCP段。比如由多个数据包组成的HTTP协议的应答包,如下 这里的分段是指:上层协议HTTP的应答由多个分段组...

Nginx code 常用状态码学习小结

最近了解下Nginx的Code状态码,在此简单总结下。一个http请求处理流程: 一个普通的http请求处理流程,如上图所示:A -> client端发起请求给nginxB -> nginx处理后,将请求转发到uwsgi,并等待结果C -> uwsgi处理完请求后,返回数据给nginxD -> nginx将处理结果返回给客户端每个...

axios 学习文档

什么是 axios? Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。axios Github 特性 从浏览器中创建 XMLHttpRequests 从 node.js 创建 http 请求 支持 Promise API 拦截请求和响应 转换请求数据和响应数据 取消请求 自动转换 JSON 数据 客户端支持...