断点续传

1.断点续传——下载

其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。
以七牛文件服务器为例,使用curl命令模拟分段请求,请求时把 responsheader dump 到一个文件里: 命令如下:

cd /tmp/range/  
curl -D "/tmp/range/range-response-header.txt" -H 'Range: bytes=0-1198680' https://ghost.oss.sherlocky.com/0/90/73d58da3592f5ada5d5f690061145.jpg > /tmp/range/test-range.jpg  
curl -D "/tmp/range/range-response-header.txt" -H 'Range: bytes=1198681-' https://ghost.oss.sherlocky.com/0/90/73d58da3592f5ada5d5f690061145.jpg >> /tmp/range/test-range.jpg  

服务器返回如下:

HTTP/1.1 206 Partial Content  
Date: Tue, 18 Apr 2017 11:42:35 GMT  
Content-Type: image/jpeg  
Content-Length: 1198681  
Connection: keep-alive  
Server: nginx  
Accept-Ranges: bytes  
Access-Control-Allow-Origin: *  
Access-Control-Expose-Headers: X-Log, X-Reqid  
Access-Control-Max-Age: 2592000  
Cache-Control: public, max-age=31536000  
Content-Disposition: inline; filename="73d58da3592f5ada5d5f690061145.jpg"  
Content-Transfer-Encoding: binary  
ETag: "Fiy2dGxdQOOt7ZHdswwq_9Iw9AM4"  
Last-Modified: Tue, 05 Apr 2016 16:28:16 GMT  
X-Log: mc.g:2;IO:76  
X-Reqid: h00AADBcnB8se7YU  
X-Qiniu-Zone: 0  
Content-Range: bytes 0-1198680/2198680  
X-Ser: BC23_dx-henan-luoyang-2-cache-8  
X-Cache: MISS from BC23_dx-henan-luoyang-2-cache-8(baishan)  

所谓断点续传,也就是要从文件已经下载的地方开始继续下载。所以在客户端浏览器传给 Web服务器的时候要多加一条信息--从哪里开始。

正常的下载请求:

curl -D "/tmp/range/range-response-header-all.txt" https://ghost.oss.sherlocky.com/0/90/73d58da3592f5ada5d5f690061145.jpg > /tmp/range/test-range-all.jpg  

服务器返回以下信息:

HTTP/1.1 200 OK  
Date: Tue, 18 Apr 2017 11:45:37 GMT  
Content-Type: image/jpeg  
Content-Length: 2198680  
Connection: keep-alive  
Server: nginx  
Accept-Ranges: bytes  
Access-Control-Allow-Origin: *  
Access-Control-Expose-Headers: X-Log, X-Reqid  
Access-Control-Max-Age: 2592000  
Cache-Control: public, max-age=31536000  
Content-Disposition: inline; filename="73d58da3592f5ada5d5f690061145.jpg"  
Content-Transfer-Encoding: binary  
ETag: "Fiy2dGxdQOOt7ZHdswwq_9Iw9AM4"  
Last-Modified: Tue, 05 Apr 2016 16:28:16 GMT  
X-Log: mc.g;IO  
X-Reqid: mysAAE0EYl5We7YU  
X-Qiniu-Zone: 0  
X-Ser: BC23_dx-henan-luoyang-2-cache-8  
X-Cache: MISS from BC23_dx-henan-luoyang-2-cache-8(baishan)  

和前面服务器返回的信息比较一下,就会发现增加了一行:
Content-Range: bytes 0-1198680/2198680
返回的代码也改为 206 了,而不再是 200 了。
注意:如果用户的请求中含有range ,则服务器的相应代码为206。

2.断点续传——上传

请求头说明

请求头 说明
Content-Disposition attachment, filename=“上传的文件名”
Content-Type 待上传文件的mime type,如application/octet-stream(注:不能为multipart/form-data)
X-Content-Range 待上传文件字节范围,如第一片段bytes 0-51200/511920,最后一个片段bytes 460809-511919/511920(注:文件第一个字节标号为0,最后一个字节标号为n-1,其中n为文件字节大小)
X-Session-ID 上传文件的标识,由客户端随机指定.因为是断点续传,客户端必须确保同一个文件的所有片段上传标识一致
Content-Length 上传片段的大小

3.http/1.1 Range和Content-Range

在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时才用到 RangeContent-Range 实体头。
Range
用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

Range:(unit=first byte pos)-[last byte pos]  

Content-Range
用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式:

Content-Range:bytes (unit first byte pos)-[last byte pos]/[entity legth]  

请求下载整个文件:

GET /test.rar HTTP/1.1  
Connection: close  
Host: 116.1.219.219  
Range: bytes=0-801 //一般请求下载整个文件是 bytes=0- 或不用这个头  

一般正常回应

HTTP/1.1 206 Partial Content # 返回状态码是206  
Content-Length: 801  
Content-Type: application/octet-stream  
Content-Range: bytes 0-800/801 //801:文件总大小  

假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如4个部分,然后创建4个线程,每个线程负责下载一个部分,如果文件大小为 403个byte,那么你的分割方式可以为:0-99 (前100个字节),100-199(第二个100字节),200-299(第三个100字节),300-402(最后103个字节)。
分割完成,每个线程都明白自己的任务,比如线程3的任务是负责下载200-299这部分文件,现在的问题是:线程3发送一个什么样的请求报文,才能够保证只请求文件的200-299字节,而不会干扰其他线程的任务。这时,我们可以使用HTTP1.1的Range头。Range头域可以请求实体的一个或者多个子范围,Range的值为0表示第一个字节,也就是Range计算字节数是从0开始的:

    表示头500个字节:Range: bytes=0-499
    表示第二个500字节:Range: bytes=500-999
    表示最后500个字节:Range: bytes=-500
    表示500字节以后的范围:Range: bytes=500-
    第一个和最后一个字节:Range: bytes=0-0,-1
    同时指定几个范围:Range: bytes=500-600,601-999

所以,线程3发送的请求报文必须有这一行:

    Range: bytes=200-299

服务器接收到线程3的请求报文,发现这是一个带有Range头的GET请求,如果一切正常,服务器的响应报文会有下面这行:

HTTP/1.1 206 OK  

表示处理请求成功,响应报文还有这一行

Content-Range: bytes 200-299/403  

斜杠后面的403表示文件的大小,通常Content-Range的用法为:

     . The first 500 bytes:
     Content-Range: bytes 0-499/1234

     . The second 500 bytes:
     Content-Range: bytes 500-999/1234

     . All except for the first 500 bytes:
     Content-Range: bytes 500-1233/1234

     . The last 500 bytes:
     Content-Range: bytes 734-1233/1234