HTTP协议的分块传输编码


前段时间在弄HTTP协议的解析,大体上感觉还行,但是被一个地方卡了很久(之前没有系统学习/了解这方面的知识,还是有所疏漏,不过只要知道了问题在哪,学起来还是很快的~),后来在高手指点下,以及自己买了本《HTTP权威指南》好好看了看,还是有点效果的,记录如下:

==

通常,HTTP应答消息中发送的数据是整个发送的,Content-Length消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。通常数据块的大小是一致的,但也不总是这种情况。

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

除非使用了分块编码,否则Content-Length首部就是带有实体主体的报文必须使用的。使用Content-Length首部是为了能够检测出服务器崩溃而导致的报文截尾,并对共享持久连接的多个报文进行正确分段。

==

HTTP 1.1引入分块传输编码提供了以下几点好处:
  1. HTTP分块传输编码允许服务器为动态生成的内容维持HTTP持久链接。通常,持久链接需要服务器在开始发送消息体前发送Content-Length消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。[ http://tools.ietf.org/html/rfc2616#section-3.6.1 ]
  2. 分块传输编码允许服务器在最后发送消息头字段。对于那些头字段值在内容被生成之前无法知道的情形非常重要,例如消息的内容要使用散列进行签名,散列的结果通过HTTP消息头字段进行传输。没有分块传输编码时,服务器必须缓冲内容直到完成后计算头字段的值并在发送内容前发送这些头字段的值。
  3. HTTP服务器有时使用压缩gzipdeflate)以缩短传输花费的时间。分块传输编码可以用来分隔压缩对象的多个部分。在这种情况下,块不是分别压缩的,而是整个负载进行压缩,压缩的输出使用本文描述的方案进行分块传输。在压缩的情形中,分块编码有利于一边进行压缩一边发送数据,而不是先完成压缩过程以得知压缩后数据的大小。

==

chunked_transfer_encoding

编码的应答
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1C
and this is the second one

3
con
8
sequence
0
编码应答的解释

前两个块的数据中包含有显式的\r\n字符。

"This is the data in the first chunk\r\n" (37 字符 => 十六进制: 0x25)
"and this is the second one\r\n"          (28 字符 => 十六进制: 0x1C)
"con"                                     (3  字符 => 十六进制: 0x03)
"sequence"                                (8  字符 => 十六进制: 0x08)

应答需要以0长度的块( “0\r\n\r\n”)结束

解码的数据
This is the data in the first chunk
and this is the second one
consequence

==

HTTP协议中确定实体主体长度的规则:

  • 如果特定的HTTP报文类型中不允许带有主体,就忽略Content-Length首部,它是对主体进行计算的;
  • 如果报文中含有描述传输编码的Transfer-Encoding首部(不采用默认的HTTP“恒等”编码),那实体就应该由一个称为“零字节块”(zero-byte chunk)的特殊模式结束,除非报文已经因连接关闭而结束。
  • 如果报文中含有Content-Length首部(并且报文类型允许有实体主体),而且没有非恒等的Transfer-Encoding首部字段,那么Content-Length的值就是主体的长度。如果收到的报文中既有Content-Length首部字段又有非恒等的Transfer-Encoding首部字段,那就必须忽略Content-Length,因为传输编码会改变实体主体的表示和传输方式(因此可能就会改变传输的字节数)。
  • 如果报文使用了multipart/byteranges(多部分/字节范围)媒体类型,并且没有用Content-Length首部指出实体主体的长度,那么多部分报文中的每个部分都要说明它自己的大小。
  • 如果上面的规则都不匹配,实体就在连接关闭的时候结束。实际上,只有服务器可以使用连接关闭来指示报文的结束。客户端不能用关闭连接来指示客户端报文的结束,因为这样会使服务器无法发回响应。

 

相关/参考链接:

 


《 “HTTP协议的分块传输编码” 》 有 4 条评论

  1. https://en.wikipedia.org/wiki/Chunked_transfer_encoding
    https://zh.wikipedia.org/wiki/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding

    HTTP 协议中的 Transfer-Encoding
    https://imququ.com/post/transfer-encoding-header-in-http.html

    文章5:http协议中content-length 以及chunked编码分析
    http://blog.csdn.net/yankai0219/article/details/8269922
    http://blog.sae.sina.com.cn/archives/3795

    【原创】HTTP 协议中的 chunked 编码
    https://yq.aliyun.com/articles/42170

    HTTP协议之chunk编码(分块传输编码)
    http://blog.csdn.net/xifeijian/article/details/42921827
    `
    HTTP 1.1引入分块传输编码提供了以下几点好处:
    1、HTTP分块传输编码允许服务器为动态生成的内容维持HTTP持久连接。通常,持久链接需要服务器在开始发送消息体前发送Content-Length消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。[动态内容,content-length无法预知]
    2、分块传输编码允许服务器在最后发送消息头字段。对于那些头字段值在内容被生成之前无法知道的情形非常重要,例如消息的内容要使用散列进行签名,散列的结果通过HTTP消息头字段进行传输。没有分块传输编码时,服务器必须缓冲内容直到完成后计算头字段的值并在发送内容前发送这些头字段的值。[散列签名,需缓冲完成才能计算]
    3、HTTP服务器有时使用压缩 (gzip或deflate)以缩短传输花费的时间。分块传输编码可以用来分隔压缩对象的多个部分。在这种情况下,块不是分别压缩的,而是整个负载进行压缩,压缩的输出使用本文描述的方案进行分块传输。在压缩的情形中,分块编码有利于一边进行压缩一边发送数据,而不是先完成压缩过程以得知压缩后数据的大小。[gzip压缩,压缩与传输同时进行]

    一般情况HTTP的Header包含Content-Length域来指明报文体的长度。有时候服务生成HTTP回应是无法确定消息大小的,比如大文件的下载,或者后台需要复杂的逻辑才能全部处理页面的请求,这时用需要实时生成消息长度,服务器一般使用chunked编码。
    `

  2. HTTP协议冷知识大全
    https://mp.weixin.qq.com/s/aekcsgLG6jZw3LeF3R9ssQ
    `
    如果不用HTTPS,HTTP协议如何安全的传输密码信息?
    文件路径攻击
    DNS欺骗
    谨慎使用外部的HTTP代理
    413 Request Entity Too Large
    414 Request-URI Too Long
    202 Accepted (常用于异步请求)
    POST提交数据的方式
    Cookie
    Cookie的两个重要属性
    CSRF(Cross-Site Request Forgery)
    XSS(Cross Site Scripting)
    跨域
    JSONP(JSON Padding)
    CORS(Cross-Origin Resource Sharing)
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注