chunked & content-length
chunked & content-length
Content-Encoding & Transfer-Encoding
refer to : https://zq99299.github.io/note-book2/http-protocol/04/02.html#%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93
上次我们谈到了 HTTP 报文里的 body,知道了 HTTP 可以传输很多种类的数据,不仅是文本,也能传输图片、音频和视频。
早期互联网上传输的基本上都是只有几 K 大小的文本和小图片,现在的情况则大有不同。网页里包含的信息实在是太多了,随随便便一个主页 HTML 就有可能上百 K,高质量的图片都以 M 论,更不要说那些电影、电视剧了,几 G、几十 G 都有可能。
相比之下,100M 的光纤固网或者 4G 移动网络在这些大文件的压力下都变成了 「小水管」,无论是上传还是下载,都会把网络传输链路挤的「满满当当」。
所以,如何在有限的带宽下高效快捷地传输这些大文件就成了一个重要的课题 。这就好比是已经打开了冰箱门(建立连接),该怎么把大象(文件)塞进去再关上门(完成传输)呢?
今天我们就一起看看 HTTP 协议里有哪些手段,能解决这个问题
数据压缩
还记得上一讲中说到的 数据类型与编码 吗?如果你还有印象的话,肯定能够想到一个最基本的解决方案,那就是 数据压缩 ,把大象变成小猪佩奇,再放进冰箱。
通常浏览器在发送请求时都会带着 Accept-Encoding 头字段,里面是 浏览器支持的压缩格式列表 ,例如 gzip、deflate、br 等,这样服务器就可以从中选择一种压缩算法,放进 Content-Encoding 响应头里,再把原数据压缩后发给浏览器。
如果压缩率能有 50%,也就是说 100K 的数据能够压缩成 50K 的大小,那么就相当于在带宽不变的情况下网速提升了一倍,加速的效果是非常明显的。
不过这个解决方法也有个缺点,gzip 等压缩算法通常只对文本文件有较好的压缩率,而图片、音频视频等多媒体数据本身就已经是高度压缩的,再用 gzip 处理也不会变小(甚至还有可能会增大一点),所以它就失效了。
不过数据压缩在处理文本的时候效果还是很好的,所以各大网站的服务器都会使用这个手段作为保底。例如,在 Nginx 里就会使用 gzip on
指令,启用对 text/html
的压缩。
分块传输
在数据压缩之外,还能有什么办法来解决大文件的问题呢?
压缩是把大文件整体变小,我们可以反过来思考,如果大文件整体不能变小,那就把它 拆开 ,分解成多个小块,把这些小块分批发给浏览器,浏览器收到后再组装复原。
这样浏览器和服务器都不用在内存里保存文件的全部,每次只收发一小部分,网络也不会被大文件长时间占用,内存、带宽等资源也就节省下来了。
这种 化整为零 的思路在 HTTP 协议里就是 chunked 分块传输编码,在响应报文里用头字段 Transfer-Encoding: chunked 来表示,意思是报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送。
这就好比是用魔法把大象变成乐高积木,拆散了逐个装进冰箱,到达目的地后再施法拼起来满血复活。
分块传输也可以用于流式数据 ,例如由数据库动态生成的表单页面,这种情况下 body 数据的长度是未知的 ,无法在头字段 Content-Length 里给出确切的长度,所以也只能用 chunked 方式分块发送。
Transfer-Encoding: chunked
和 Content-Length
这两个字段是 互斥的 ,也就是说响应报文里这两个字段不能同时出现,一个响应报文的传输要么是长度已知,要么是长度未知(chunked),这一点你一定要记住。
下面我们来看一下分块传输的编码规则,其实也很简单,同样采用了明文的方式,很类似响应头。
- 每个分块包含两个部分,长度头和数据块;
- 长度头是以 CRLF(回车换行,即
\r\n
)结尾的一行明文,用 16 进制数字表示长度; - 数据块紧跟在长度头后,最后也用 CRLF 结尾,但数据不包含 CRLF;
- 最后用一个长度为 0 的块表示结束,即
0\r\n\r\n
。
听起来好像有点难懂,看一下图就好理解了:
实际样例
我们来看下,实际的例子:
HTTP/1.1 200 OK
Content-Disposition: attachment; filename="a4adcdf1c769c8327e0b154ee764dc28.iso"
Content-Encoding: gzip
Content-Security-Policy: default-src 'self' 'unsafe-eval' 'unsafe-inline';
Content-Type: application/octet-stream
Last-Modified: Wed, 17 Jul 2024 08:56:36 GMT
Referrer-Policy: strict-origin-when-cross-origin
Server: MinIO Console
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Xss-Protection: 1; mode=block
Date: Tue, 13 Aug 2024 11:17:34 GMT
Connection: close
Transfer-Encoding: chunked
文章作者:Administrator
文章链接:http://localhost:8090//archives/1723936916535
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0 许可协议,转载请注明出处!
评论