目录
  1. 1. HTTP–断点续传和多线程下载
    1. 1.1. Range
    2. 1.2. Content-Range
    3. 1.3. 总结:
      1. 1.3.1. 可能的问题
    4. 1.4. 多线程下载
HTTP--断点续传和多线程下载

HTTP–断点续传和多线程下载

总结与《HTTP-断点续传和多线程下载》和《图解HTTP》

  HTTP 的断点续传依赖于首部的两个字段 :Range 和 Content-range

  • Range:客户端发请求的范文(闭区间)
  • Content-range:服务端返回当前请求范围和文件总大小

HTTP 1.1 协议开始支持文件的部分传输,续传成功返回 206。

Range

  • 用于请求头,请求内容的第一个字节和最后一个字节的位置,一般格式:

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

注意事项

  1. 这个数据区间是闭合的区间,起始值是 0,bytes = 0-1,指的是 0 和 1 两个字节的内容。
  2. Range :bytes = -200,前面这里加了个负号,表示的是结尾处的 200 字节文件
  3. 如果后面那个数小于前面那个数,即结束范围小于起始范围这是不合理的,即这个 Range 请求时无效的,服务器会无视该 Range 请求,而返回一个 200 ,把整个文件发给客户端。
  4. 如果后面那个数大于文件的长度,那么这个 Range 请求时不能被满足的,server 会回应一个 416:Requested range not satisfiable

示例解释:

Range: bytes=0-499 表示第 0-499 字节范围的内容

Range: bytes=500-999 表示第 500-999 字节范围的内容

Range: bytes=-500 表示最后 500 字节的内容

Range: bytes=500- 表示从第 500 字节开始到文件结束部分的内容

Range: bytes=0-0,-1 表示第一个和最后一个字节

Range: bytes=500-600,601-999 同时指定几个范围

Content-Range

  • 用于响应头中,在发出带 Range 的请求后,服务器会在 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 200 OK

Content-Length: 801

Content-Type: application/octet-stream

Content-Range: bytes 0-800/801 //801:文件总大小

而在响应完成后,返回的响应头内容也不同:

HTTP/1.1 200 Ok(不使用断点续传方式)

HTTP/1.1 206 Partial Content(使用断点续传方式)

总结:

HTTP1.1协议(RFC2616)中定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:

  1. 客户端下载一个1024K的文件,已经下载了其中512K
  2. 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:
    Range:bytes=512000-
    这个头通知服务端从文件的512K位置开始传输文件
  3. 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:
    Content-Range: bytes 512000-/1024000
    并且此时服务端返回的HTTP状态码应该是206,而不是200。

可能的问题

  在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?

  响应的首部字段中还有一个字段是 ETag 字段,它能告知客户端实体的标识,它是一种可将资源以字符串形式做唯一标识的方式。服务器会对每一个资源分配对应的 ETag 值。当资源更新时,ETag 值也会随之更新,生成 ETag 并没有固定的法则,都是由服务器决定比如:md5

  而客户端的请求头中也有一个首部字段是 if-Range ,If-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时候。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据。

多线程下载

  假设你要开发一个多线程下载工具,你会自然的想到把文件分割成多个部分,比如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开始的。

文章作者: Archiver
文章链接: https://www.kaiming66.com/2020/02/16/Java/HTTP--%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E5%92%8C%E5%A4%9A%E7%BA%BF%E7%A8%8B%E4%B8%8B%E8%BD%BD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Archiver`s Blog
打赏
  • 微信
  • 支付寶

评论