我们知道HTTP报文中的body不仅可以传输文本还可以传输图片、视频以及音频;
随着互联网的发展,现在随便一个HTML文件就有几百KB,如果是高质量的图片或者视频那都要M或者GB了;
我们的带宽都是固定在这些大文件面前就显的微不足道;
接下来我们就看看在HTTP协议加持下是如何在固定宽带的情况下传输这些超大文件的
数据压缩
在【HTTP Body】一文中我们介绍【数据类型与编码】中就有关于针对body报文的压缩
我们在请求头字段中使用【Accept-Encoding: gzip】告知服务器我们能接受gzip压缩类型的数据;
同时在响应头中使用【Content-Encoding:gzip】和body中把数据传递给客户端;
【数据压缩】就是把我们巨大的数据量【成年的猪猪】---> 【幼年的小猪羔子】然后在回传给客户端;
不过gzip这种压缩针对文本压缩还是很有效果的;对于图片或者音频来说,本身也是经过处理的了使用gzip的收益不大;
不过在传输文本的时候服务器还是会使用gzip作为一次【保底】;
除了压缩数据之外,HTTP还是支持分块传输的;
分块传输
分块传输也就是把数据切成很多块,分批传递给客户端客户端收到后在重新组装,思想就是减少每次数据的传输量;
在HTTP协议头字段中,针对分块传输的表现是使用【Transfer-Encoding:chunked】表示响应报文body中的数据不是一次性全部传递过来的,而是分成很多块逐个发送的;
分块传输也可以用于【流式数据】;例如数据库动态生成的表单页面;这种情况下body数据的长度是未知,那么头字段中【Content-Length】无法给出确切的长度
换句话说,在响应报文中【Content-Length】和【Transfer-Encoding:chunked】不能同时出现;一个响应报文长度要么是【已知】的要么是【未知】的;
分块传输的规则
每个分块包含两个部分。长度头和数据块;
长度头是以CRLF(回车换行,即\r\n)结尾的一行明文,用16进制数字表示长度;
数据块在长度头之后,最后用CRLF结尾,数据块不包含CRLF
最后用一个长度为0的块表示结束,即【0\r\n\r\n】
范围请求
使用场景
-
当我们观看一部电影时,去跳过片头时(拖拽进度条前进),使用到了范围请求;
这个实际上是获取一个大文件其中的片段数据;我们的分块传输并没有这个能力;
任何技术的出现都是为了满足用户需求出现的,范围请求就是为了解决上述类似场景的需求;
HTTP协议允许客户端在请求头里使用专用字段获取文件的一部分;
范围请求不是WEB服务器必备的功能;服务器可以在响应头字段中使用【Accept-Ranges:bytes】明确告知客户端我是不是支持的
不支持
- 不支持:服务器就返回【Accept-Ranges:none】或者就不返回对应的字段;
支持
【Range】是HTTP范围请求中请求头的专用字段,格式是【bytes=x-y】x和y是以字节为单位的数据范围;
范围必须从0计数【0-9】表示前10个字节,【10-19】表示第二个10字节;
灵活的Range格式
【0-】表示从数据起点到终点,表示整个文件
【10-】表示从第10个字节开始到文档结尾;
【-1】表示最后一个字节;
【-10】表示文档末尾倒数10个字节;
服务器收到Range的处理
检查范围的合法性,如果范围越界了,服务器就会返回状态码【416】;
范围正确的话,就根据Range头计算返回数据的片段;此时的状态码为【206 Partial Content】
-
同时服务器会在响应头字段中添加一个【Content-Range】告诉片段的实际偏移量和资源的总大小
- 这里在说下,响应头中会返回【Accept-Range】用于告知服务器是否支持范围请求的;
响应头中的【Content-Range】
格式是 【bytes x-y/length】与请求头中的Range区别在于没有【=】,范围区间后多了【总长度length】
应用场景
视频拖拽进度
下载工具里的多段下载,断点续传
大概思路
发送一个HEAD请求,查看服务器是否支持范围请求,同时能获取到文件的大小
开启线程,线程中发起的网络请求使用Range字段划分出各自负责的下载的片段;
多段数据
上文说的范围请求一次只能获取一个数据片段,当在请求头【Range】中使用多个【x-y】就能一次性获取多个片段数据了,也就是【多段数据】
上述【多段数据】使用情况使用特殊的MIME 【multipart/byteranges】表示响应报文中body是由多段数据组成的;
同时使用【boundary=xxx】标识出每段之间的分隔标记;
直接上示意图