前言

当下载电影时,我常常会想中断下载后,为什么点击开始时会在中断的地方继续下载呢?
又或者在看在线电影时,为什么可以按着播放条拖动就能看到想看的片段呢?

http的range请求将解决以上困惑。

多线程、断点续传、随机点播等的场景的步骤

1、客户端明确任务:从哪开始下载

  • 本地是否已有部分文件:文件已下载部分在服务器端发生改变?
  • 使用几个线程并发下载

2、下载文件的指定部分内容
3、下载完毕后拼装成统一的文件

HTTP Range规范

在RFC7233中有详细介绍
1、允许服务器基于客户端的请求只发送响应包体的一部分给到客户端,而客户端自动将多个片段的包体组合成完整的体积更大的包体。

  • 支持断点续传
  • 支持多线程下载
  • 支持视频播放器实时拖动

2、服务器通过Accept-Range头部表示是否支持Range请求

  • Accept-Ranges = acceptable-ranges
  • 例如:
    Accept-Ranges: bytes: 支持;
    Accept-Ranges: none: 不支持

Range请求范围的单位

基于字节为单位的时候,举例:设置响应体长度为10000

  • 第1个500字节:
    bytes=0-499 // 从0开始
  • 第2个500字节:
    bytes=500-999
    bytes=500-600, 601-999
    bytes=500-700, 601-999
  • 最后1个500字节
    bytes=-500
    bytes=9500-
  • 仅要第一个和最后一个字节:bytes=0-0, -1

通过Range头部传递请求范围,如:Range: bytes=0-499

测试

下面用一些小例子有测试一下。
用node搭了一个简单的服务器,返回的数字是22个字节的响应体

'Hello World 0123456789';

现在用curl命令获取全部的响应体,然后访问0-5的字节段:

-H参数添加 HTTP 请求的标头。
上面的命令就是添加HTTP头Range: bytes=0-5。
返回的是Hello (加上空格)一共六个字节。

现在获取第21个字节及以后的字节段,就可以用20-:


返回的是89

Range条件请求

  • 如果客户端已经得到了Range响应的一部分,并想在这部分响应未过期的情况下,获取其他部分的响应
    常与If-Unmodified-Since或者If-Match头部共同使用
  • If-Range = entity-tag / HTTP-date
    可以使用Etag或者Last-Modified

测试

下面用etag测试一下Range条件请求

首先获取0-5字节段

然后用-I来看看生成Hello 时服务器生成Etag的值

接下来,用这个值放到If-Match中获取6-10字节段:World

如果Etag发生了变化,来看看结果会怎么样,将最后的0改为1


返回412 Precondition Failed

结论

通过条件请求可以判断两次下载之间,服务器端资源有没有发生变化。如果发生了变化,就可以通过412这个响应知道,资源已经发生了变化。

服务器响应

如果只获取部分的body,那么服务器端返回的响应码不是200,而是206。
206 Partial Content

  • Content-Range头部:显示当前片段响应体在完整包体中的位置

  • Content-Range = byte-content-range / other-content-range
    { btye-content-range = bytes-unit SP (byte-range-resp / unsatisfied-range)
    byte-range-resp = byte-range '/' (complete-length / '')
    complete-length = 1
    DIGIT // 完整资源的大小,如果未知则用*号替代
    bytr-range = first-byte-pos "-" last-byte-pos }

  • 例如:
    1、Content-Range: bytes 42-1233/1234
    2、Content-Range: bytes 42-1233/*

测试

用一个视频播放的例子来看看206响应的样子。 

416 Range Not Statisfiable

  • 请求范围不满足实际资源的大小,其中Content-Range中的complete-length显示完整响应的长度,例如
    Content-Range: bytes */1234

测试

如果获取范围超出实际资源的大小,比如获取30-40。返回416

200 OK

  • 服务器不支持Range请求时,则以200返回完整的响应包体

多重范围与multipart

  • 请求:
    Range: bytes=0-50, 100-150
  • 响应:
    Content-Type: multipart/byteranges; boundary=...

测试

获取5-10, 10-15片段。

总结

1、客户端通过Range头部传递请求范围

2、服务端返回Accept-Range头部表示是否支持Range请求。

3、客户端如果在得到Range响应的一部分,并想在这部分响应未过期的情况下,获取其他部分的响应,可以用If-Range头部使用Etag或者Last-Modified为值。

4、只获取部分的body,服务器返回206响应码,其中Content-Range头部显示当前片段响应体在完整包体中的位置

5、客户端想多重范围下载资源,在Range头部的格式为Range: bytes=0-50, 100-150...(用逗号分隔)
响应头部Content-Type: multipart/byteranges; boundary=...

作者: zhangwinwin
链接:Http系列:断点续传与多线程下载
来源:github

Http系列:断点续传与多线程下载的更多相关文章

  1. 图解:HTTP 范围请求,助力断点续传、多线程下载的核心原理

    题图:by Charles Loyer 一.序 Hi,大家好,我是承香墨影! HTTP 协议在网络知识中占据了重要的地位,HTTP 协议最基础的就是请求和响应的报文,而报文又是由报文头(Header) ...

  2. 网络编程之PC版与Android手机版带断点续传的多线程下载

    一.多线程下载         多线程下载就是抢占服务器资源         原理:服务器CPU 分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服 ...

  3. ASP.NET文件下载各种方式比较:对性能的影响、对大文件的支持、对断点续传和多线程下载的支持

    asp.net里提供了多种方式,从服务器端向客户端写文件流,实现客户端下载文件.这种技术在做防下载系统时比较有用处.主些技术主要有:WriteFile.TransmitFile和BinaryWrite ...

  4. 基于http的断点续传和多线程下载

    HTTP协议的GET方法,支持只请求某个资源的某一部分: 206 Partial Content 部分内容响应: Range 请求的资源范围: Content-Range 响应的资源范围: 断点续传: ...

  5. java多线程下载和断点续传

    java多线程下载和断点续传,示例代码只实现了多线程,断点只做了介绍.但是实际测试结果不是很理想,不知道是哪里出了问题.所以贴上来请高手修正. [Java]代码 import java.io.File ...

  6. Java--使用多线程下载,断点续传技术原理(RandomAccessFile)

    一.基础知识 1.什么是线程?什么是进程?它们之间的关系? 可以参考之前的一篇文章:java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器 简 ...

  7. android 多线程下载 断点续传

    来源:网易云课堂Android极客班第八次作业练习 练习内容: 多线程 asyncTask handler 多线程下载的原理 首先获取到目标文件的大小,然后在磁盘上申请一块空间用于保存目标文件,接着把 ...

  8. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  9. Java开发之多线程下载和断点续传

    代码实现了多线程下载和断点续传功能 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream ...

随机推荐

  1. 从零开始部署发布Java项目到服务器的Docker中

    本以为很简单,由于没用过docker和java,本文将会阐述一路遇到的拦路虎. 首先,写好Java项目,本地跑通. 可能会遇到的问题: 1.jar包正常运行,war包404: 如何打包很多教程都有介绍 ...

  2. CentOS7的防火墙以及selinux介绍/安装telnet命令/安装netstat与ifconfig命令

    简介:firewall防火墙的使用 防火墙:主要用户信息安全防护,主要有软件防火墙和硬件防火墙.firewalld防火墙是软件防火墙,在centos7 之前默认采用的防火墙是iptables,而在ce ...

  3. 记录第一次使用Vivado——以全加器为例子

    从altera转战xilinx,经典的FPGA到ZYNQ系列,第一站就是先熟悉编译软件Vivado.我就直接跳过软件安装部分了,如有疑问,可以在评论区提出来,我看到了就帮你解答. 首先是是打开界面 然 ...

  4. 痞子衡嵌入式:MCUXpresso IDE下SDK工程导入与workspace管理机制

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是MCUXpresso IDE下SDK工程导入与workspace管理机制. MCUXpresso IDE是恩智浦软件团队倾注很大心血研发 ...

  5. maven项目修改名称后,打包名称和现在名称不一致

    将pom.xm文件中 <artifactId>health</artifactId> 修改成现在项目名称,然后 maven clean ->maven install 如 ...

  6. 根据租户id获取部门树状结构有父子结构的数据list

    /** * 根据租户id获取部门树状结构 * @param tenantId * @return */ @GetMapping("getDeptTreeList") public ...

  7. tcp聊天

    package tcp; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; i ...

  8. Lightweight Render Pipeline

    (翻译) Lightweight Render Pipeline (LWRP),轻量级渲染管线,是一个Unity预制的Scriptable Render Pipeline (SRP).LWRP可以为移 ...

  9. 分布式一致性协议 Raft

    分布式领域,CP模型下 数据一致性协议至关重要,不然两边数据不一致容易出现数据读混乱问题.像Etcd Consul  zookeeper Eureka ,Redis集群方案这些中间件 都有一致性算法来 ...

  10. 阿里技术专家详解 Dubbo 实践,演进及未来规划

    Dubbo 整体介绍 Dubbo 是一款高性能,轻量级的 Java RPC 框架.虽然它是以 Java 语言来出名的,但是现在我们生态里面已经有 Go.Python.PHP.Node.JS 等等语言. ...