欢迎加入QQ讨论群258996829
麦子学院 头像
苹果6袋
6
麦子学院

断点续传详解

发布时间:2016-07-05 23:54  回复:0  查看:2790   最后回复:2016-07-05 23:54  
HTTP学习中,断点续传是很实用也很常用的知识点,我们从断点续传的原理开始讲起。
HTTP文件断点续传的原理
前几天一个同事跑过来找我说,我们在广告素材视频这块想做断点续传,就是这次某个视频缓存到一半,下次不用重头开始,可以在原来停留得位置开始继续下载 . 以提供更好的用户体验。
同时说需要我们支持吐素材地址的业务接口告诉终端最后修改时间 / 文件签名( md5 ),用这个用来判断我当前要下的文件有没有变化,同时告诉终端文件的 Size 大小 .
我一细想,这个问题压根不需要通过改变现有接口提供更多的数据来做 . 下面从原理实现上简单说下:
关键点:
对于断点续传,关键点是两个:
1.  终端知道当前的文件和上一次加载的文件是不是内容发生了变化,如果有变化,需要重新从 offset 0  的位置开始下载
2.  终端记录好上次成功下载到的 offset ,告诉 server ,server 端支持从特定的 offset  开始吐数据
文件变化感知:
前置业务接口方案:
对于关键点 1 ,对于决定大部分产品的业务场景,可以通过前置业务接口解决;这里简单介绍一下:
对于非下载工具类的产品,如视频 APP (奇艺 , 优酷),视频播放前会请求相关业务的信息,主要返回片子叫什么名字,主要演员等等一些列信息,同时会返回一个对于播放最重要的信息 —— 播放地址。
播放地址就是我们可以做文章的地方,如果《太子妃第一集》这个片子更新了(被广电要求减掉某个污的画面),可以后端系统让这个业务接口吐不同的播放地址 / 一个不同的 url 参数 (?ver=1.1)/ 位置参数 (#ver1.1) 。这样纯天然的 URL 变化能纯天然的让终端认为不是同一个片子,而需要重新加载。
HTPP  标准 ETAG 方案:
没有业务接口的下载工具类的如何解决呢?
下载工具类的没有前置接口,可以使用 HTTP  ETAG 来标识是否文件已经修改。
ETAG 原理:如果 URL 上的资源内容改变,一个新的不一样的 ETag 就会被分配。用这种方法使用 ETag 即类似于指纹,并且他们能够被快速地被比较,以确定两个版本的资源是否相同。 ETag 的比较只对同一个 URL 有意义 —— 不同 URL 上的资源的 ETag 值可能相同也可能不同,从他们的 ETag 的比较中无从推断。
ETAG HTTP 的一个可选字段,且没有规范他的实现;实际上业内用的比较多的就是使用 MD5 签名的方式来生成 (linux shell md5sum)
典型用法:
server 端:  Nginx >1.3.3  自带有 ETAG module ,  当然同时也可以在业务代码里 SetHeaders 加一个 ETAG 字段
client 端:
第一次请求时:
String etag = httpURLConnection.getHeaderField("ETag");
ETag: "b428eab9654aa7c87091e"
第二次请求(断点续传时):
httpURLConnection.setRequestProperty(“If-None-Match”, "b428eab9654aa7c87091e");
If-None-Match: "b428eab9654aa7c87091e"
如果 ETag 值匹配,这就意味着资源没有改变,服务器便会发送回一个极短的响应,包含 HTTP “304  未修改 的状态。 304 状态告诉客户端,它的缓存版本是最新的,并应该使用它。
然而,如果 ETag 的值不匹配,这就意味着资源很可能发生了变化,那么,一个完整的响应就会被返回,包括资源的内容,就好像 ETag 没有被使用。这种情况下,客户端可以用新返回的资源和新的 ETag 替代先前的缓存版本。
续传支持:
对于一个 C/C++ 程序员,第一时间会得出一个系统级实现方案:
1.  客户端传当前的 offset
2. server seek 到文件特定的 offset 开始读取往 http connection 吐数据
不过我们深处在一个开放方案和标准不断完善的时代,不需要自己实现一个(这也是像我这样的 C/C++ 研发工程师越来越没落的原因) , 来看看 HTTP 协议是怎么解决这个问题的:
HTTP Range 字段:
Range :  用于客户端到服务器端的请求,可通过该字段指定下载文件的某一段大小,及其单位。典型的格式如:
Range: bytes=0-499  下载第 0-499 字节范围的内容  
Range: bytes=500-999  下载第 500-999 字节范围的内容  
Range: bytes=-500  下载最后 500 字节的内容  
Range: bytes=500-  下载从第 500 字节开始到文件结束部分的内容
来个简单粗暴的例子
curl --header "Range: bytes=0-20000" xxx.com/memcache.pdf -o part1
curl --header "Range: bytes=20001-223651" xxx.com/memcache.pdf -o part2
cat part1 part2 >> a.pdf
原文来自:大熊先生
您还未登录,请先登录

热门帖子

最新帖子