http的chunked协议

Content-Length是用来标识http的body有多少个字节,但当要传输的数据是一直产生的,或者是无法提前知道 body有多少字节时,就可以使用http/1.1的 chunked编码协议。这就是所谓的流式数据传输。特别注意,http2有自己的流式数据传输解决方案,并不使用chunked协议,所以此协议只适用于http/1.1版本。

当不写Content-Length时,只需要写Transfer-Encoding: chunked即可。无论是客户端请求,还是服务端返回都可以使用。body数据格式为:

4\r\n
Wiki\r\n
5\r\n
pedia\r\n
E\r\n
 in\r\n
\r\n
chunks.\r\n
0\r\n
\r\n

每一个chunk都是以一个16进制编码的数字独占一行打头,该16进制为字符串编码,表明接下来的chunk长度。末尾以0长度结尾,表明整个数据传输完成。由此可见,chunked协议,保持了一个长久的http连接。

值得注意,默认当Transfer-Encoding: chunked和Content-Encoding: gzip同时使用时,操作流程是这样的:创建一个gzip.GzipFile()文件对象,然后将原始数据分块依次写入该对象,每写一块,就读取一次压缩结果,然后进行chunked编码,写入socket连接,当原始数据全部写完,就可以关闭GzipFile对象,并拿到最末尾的压缩块,写入socket,结果返回结束。理论上支持chunked编码的客户端,可以逐步接收,逐步解压,逐步解析结果。这也就是利用gzip的流式压缩,结合chunked编码,实现服务端和客户端的流式传输,减小带宽的同时加快响应速度。从上逻辑可知:一、返回结果是一个gzip包分成了多块,而不是每块都是一个gzip包;二、由于压缩前并不知道结果会有多大,故而chunked编码不会跟Content-Length同时存在。

特别注意,如果前后端中间是由nginx做转发,nginx默认会收集完整的响应结果再返回给客户端,也就是上面提到的分块数据,最终被nginx缓存起来,再一次发给客户端。简单地说,nginx的默认行为是跟chunked编码不友好的,解决办法是让客户端发送X-Accel-Buffering: no头,或者是nginx配置proxy_buffering: no

chunked编码有效地减小了大数据传输对内存的需求,客户端可以边读取边发送,而服务端可以边接收边处理。chunked协议可以实现边传输边展现,能有效减小站点响应时间,减少http请求数量(参见facebook的big_pipe页面加载技术)。例如将多个小图片按chunk传输,减少http连续,发送header的过程。

发表于 2018年01月21日 23:19   修改于 2022年01月01日 22:23   评论:0   阅读:3294  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo