HTTP断点续传原理

作为一名程序媛我也想快点进步,希望慢慢积累吧。给自己加加油。

1. 断点续传的必要性

大部分下载类的app,都会遇到网络不好的情况,如果下载到最后一步却下载失败了,是不是会让人很头疼。如果能重试下载从上次下载的文件位置继续下载,就显得很必要了。关乎用户体验问题。非常 非常重要!!!!!😂

2.了解断点续传之前,了解下http协议。

HTTP(Hyper Text Transfer Protocol)协议是用于从万维网(www)服务器传输超文本到本地浏览器的传送协议。它是基于TCP/IP协议来传递数据的。

HTTP请求由三部分组成:状态行、请求头、请求体。

先看一下客户端请求头的一个例子:

GET /home.html HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/testpage.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Range:bytes:500-900
Cache-Control: max-age=0

这里不详细展开,我们只讨论和断点续传有关的几个请求头属性。

1.Range: 只请求实体的一部分。比如:Range:bytes:500-900
2.Etag:请求实体的唯一标识符。(可以是文件md5) 比如:ETag: “737060cd8c284d8af7ad3082f209582d”
3.Last-Modified:最后资源的更改时间。用于服务器响应头 。如: Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
4.If-Range:如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag。 例子:If-Range: “737060cd8c284d8af7ad3082f209582d”
5.Content-Range:用于服务器响应头。记录服务器返回数据的范围及文件总大小。如:Content-Range: bytes 0-499/22400
6.If-Modified-Since:如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码。 如:

If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT

有的同学可能分不清楚是客户端的请求头还是服务器端的响应头,👇下面理一下:

HTTP Request Header
Range
If-Range
If-Modified-since
HTTP Response Header
Last-Modified
Content-Range
Etag

有了这个初步了解之后再说下他们的关系。
举个例子客户端A 要从服务器端B下载文件,假设服务器B支持断点续传。

请求下载文件
客户端A
服务器端B

1、客户端第一次请求需要带上请求头 Range: bytes=0- ,如果不带默认也是表示第一次请求完整文件。
2、服务器B响应头可能包含如下属性:

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-499/22400
Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
ETag:737060cd8c284d8af7ad3082f209582d” 由服务器端生产

表示目前服务器返回了0到499bytes的数据,文件大小是22400bytes。并告诉客户端A这个文件的最后更改日期是Tue, 15 Nov 2010 12:45:26 GMT,它的唯一标识符是“737060cd8c284d8af7ad3082f209582d”,可能是文件的MD5值,也可能是其他标识符,由服务器端来定。

对于含由Range请求头的http数据,如果服务器能正常处理的话会返回:HTTP/1.1 206 Partial Content,如果不能处理Range也就是不支持断点续传的话,就会返回:HTTP/1.1 200 OK,还有一种超过资源大小范围的请求会返回416,它的意思是“Range Not Satisfiable”,
3、请求文件下载过程网络断开或者服务器挂掉,文件假如下载了20000bytes。还差2400bytes。这个时候放弃多可惜😭。
4、我们需要再次请求恢复下载。这次请求带上了一些请求头可让服务器B知道我们请求的文件从什么位置开始下载的。那么问题来了。

首先我们要确定这个URL对应的文件在服务器端没有变化。我们就用到了第2步服务器B返回给我们的响应头里的Last-ModifiedEtagLast-Modified代表初次下载时文件的更新时间,Etag代表文件的唯一标识符。

有的同学可能会问,我们有Last-Modified就够了,能判断文件是否修改了,还要Etag干嘛呢?如果服务器B的文件修改很频繁,可能是毫秒级别的,那这个Last-Modified就起不了作用了,所以Etag应运而生。

那我们恢复下载怎么把这两个属性值传回去呢,就用到了我们的If-Range。它就是用来判断服务器端文件是否发生变化的。

If-Range: Etag | HTTP-Date

它可以填写ETag值或者Last-modified 的值。

If-Range:737060cd8c284d8af7ad3082f209582d” 
If-Range: Tue, 15 Nov 2010 12:45:26 GMT

比如我们用:

If-Range: “737060cd8c284d8af7ad3082f209582d” 
Range: bytes=20000-  表示我们这次请求是从第20001个bytes的位置到文件结束部分的内容。

其中要知道If-RangeRange是配套使用的,如果没有Range,那么If-Range也没有意义。如果只有Range,那么返回的数据就是Range中指定的位置,至于数据是否正确就不保证了。
If-Range相当于条件,如果条件成立,也就是If-Range里的Etag和服务器B端文件的Etag一致,服务器B就会返回状态码是206 Partial的响应,和指定位置的响应数据。如果不满足条件,也就是文件发生了变动,那就返回状态码200 OK的响应,同时返回文件起始位置的数据。返回此时文件的Etag 或者Last-Modified

梳理了一下断点续传的知识,想想我们项目中视频下载的时候有用到。另外手机如果作为server端要支持断点续传的话也是需要处理Range和If-Range的,Client端做好断点续传的,server端也要支持才行。

如果阅读过程有发现问题请指正,大家一起进步。谢谢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章