![断点续传、秒传究竟是如何实现的?](http://img.jiangsulong.com/220410/1319521593-0.jpg)
文章插图
作者 | 喵叔
责编 | 屠敏
我们都用过网盘,不管是例如百度网盘之类的公共网盘,还是自己搭建的私有网盘,都会或多或少的涉及到断点续传和秒传 。断点续传和秒传大大提高了网盘上传的效率,下面我们就来讲解一下这两种技术的具体原理和实现,这里的讲解不涉及任何前后端编程语言,适合所有语言开发人员阅读 。
零、断点续传
这里以上传为例,下载方式的断点续传类似 。
简述原理
【断点续传、秒传究竟是如何实现的?】断点续传说白了就是将一个文件按照一定的规则人为的分割成多个小文件,然后客户端每次只上传一个小文件(当然我们也可以利用多线程技术每次上传多个小文件),服务器接收到上传过来的小文件后根据一定的规则来组合这些小文件 。如果在上传过程中出现网络中断等意外情况,下次再次上传时可以从已经上传的部分继续上传,而不是重新上传 。
详细讲解
从 HTTP1.1 协议开始就已经支出获取文件的部分内容,断点续传技术就是利用 HTTP1.1 协议的这个特点在 Header 里添加两个参数来实现的 。这两个参数分别是客户端请求时发送的 Range 和服务器返回信息时返回的 Content-Range - Range,Range 用于指定第一个字节和最后一个字节的位置,格式如下:
Range:(unit=first byte pos)-[ lastbyte pos]
Range 常用的格式有如下几种情况:
- Range:bytes=0-1024,表示传输的是从开头到第1024字节的内容;
- Range:bytes=1025-2048,表示传输的是从第1025到2048字节范围的内容;
- Range:bytes=-2000,表示传输的是最后2000字节的内容;
- Range:bytes=1024-,表示传输的是从第1024字节开始到文件结束部分的内容;
- Range:bytes=0-0,-1 表示传输的是第一个和最后一个字节 ;
- Range:bytes=1024-2048,2049-3096,3097-4096,表示传输的是多个字节范围 。
Content-Range:bytes(unit first byte pos)-[ lastbyte pos]/[entity length]
常见的格式内容如下:
Content-Range:bytes 2048-4096/10240
这里边 2048-4096 表示当前发送的数据范围,10240 表示文件总大小 。
这里我顺便说一下,如果在客户端请求报文头中,对 Range 填入了错误的范围值,服务器会返回 416 状态码 。416 状态码表示服务器无法处理所请求的数据区间,常见的情况是请求的数据区间不在文件范围之内,也就是说,Range 值,从语法上来说是没问题的,但从语义上来说却没有意义 。
注意:当使用断点续传的方式上传下载软件时 HTTP 响应头将会变为:
HTTP/1.1 206Partial Content
当然光有 Range 和 Content-Range 还是不够的,我们还要知道服务端是否支持断点续传,只需要从如下两方面判断即可:
- 判断服务端是否只 HTTP/1.1 及以上版本,如果是则支持断点续传,如果不是则不支持
- 服务端返回响应的头部是否包含 Access-Ranges,且参数内容是 bytes 符合以上两个条件即可判定位支持断点续传 。
这里的校验主要针对断点续传下载来说的 。当服务器端的文件发生改变时,客户端再次向服务端发送断点续传请求时,数据肯定就会发生错误 。这时我们可以利用 Last-Modified 来标识最后的修改时间,这样就可以判断服务器上的文件是否发生改变 。和 Last-Modified 具有同样功能的还有 if-Modified-Since,它俩的不同点是 Last-Modified 由服务器发送给客户端,而 if-Modified-Since 是由客户端发出,if-Modified-Since 将先前服务器发送给客户端的 Last-Modified 发送给服务器,服务器进行最后修改时间验证后,来告知客户端是否需要重新从服务器端获取新内容 。客户端判断是否需要更新,只需要判断服务器返回的状态码即可,206 代表不需要重新获取接着下载就行,200代表需要重新获取 。但是 Last-Modified 和 if-Modified-Since 存在一些问题:
某些文件只是修改了修改时间而内容却没变,这时我们并不希望客户端重新缓存这些文件;
某些文件修改频繁,有时一秒要修改十几次,但是 if-Modified-Since 是秒级的,无法判断比秒更小的级别;部分服务器无法获得精确的修改时间 。要解决上述问题我们就需要用到 Etag,只需将相关标记(例如文件版本号等)放在引号内即可 。
当使用校验的时候我们不需要手动实现验证,只需要利用 if-Range 结合 Last-Modified 或者 Etage 来判断是否发生改变,如果没有发生改变服务器将向客户端发送剩余的部分,否则发送全部 。
推荐阅读
- 安装MySQL数据库
- Ceph分布式存储安装部署过程
- 揭秘微粒贷、花呗、借呗、小鹅花钱、白条强开骗局
- 详析点茶点汤三义
- 让人舒服的关系:知分寸、懂换位、付真心
- 25款葡萄酒口碑评价:奔富、拉菲、醉鹅娘、慕拉、奥兰表现一般
- 方向盘变沉了、打不动是怎么回事?几个常见的方向盘故障分析
- 六招完美男人上半身
- 福鼎白茶和安吉白茶的区别
- Java线程池原理解析