一, 概述
所谓断点续传, 其实只是指下载, 也就是要从文件已经下载的地方开始继续下载. 在以前版本的 HTTP 协议是不支持断点的, HTTP/1.1 开始就支持了. 一般断点下载时才用到 Range 和 Content-Range 实体头. HTTP 协议本身不支持断点上传, 需要自己实现.
二, Range
用于请求头中, 指定第一个字节的位置和最后一个字节的位置, 一般格式:
Range: 用于客户端到服务端的请求, 可以通过改字段指定下载文件的某一段大小及其单位, 字节偏移从 0 开始. 典型格式:
Ranges: (unit=first byte pos)-[last byte pos]
Ranges: bytes=4000- 下载从第 4000 字节开始到文件结束部分
Ranges: bytes=0~N 下载第 0-N 字节范围的内容
Ranges: bytes=M-N 下载第 M-N 字节范围的内容
Ranges: bytes=-N 下载最后 N 字节内容
1. 以下几点需要注意:
(1) 这个数据区间是个闭合区间, 起始值是 0, 所以 "Range: bytes=0-1" 这样一个请求实际上是在请求开头的 2 个字节.
(2)"Range: bytes=-200", 它不是表示请求文件开始位置的 201 个字节, 而是表示要请求文件结尾处的 200 个字节.
(3) 如果 last byte pos 小于 first byte pos, 那么这个 Range 请求就是无效请求, server 需要忽略这个 Range 请求, 然后回应一个 200, 把整个文件发给 client.
(4) 如果 last byte pos 大于等于文件长度, 那么这个 Range 请求被认为是不能满足的, server 需要回应一个 416,Requested range not satisfiable.
2. 示例解释:
表示头 500 个字节: bytes=0-499
表示第二个 500 字节: bytes=500-999
表示最后 500 个字节: bytes=-500
表示 500 字节以后的范围: bytes=500-
第一个和最后一个字节: bytes=0-0,-1
同时指定几个范围: bytes=500-600,601-999
三, Content-Range
用于响应头, 指定整个实体中的一部分的插入位置, 他也指示了整个实体的长度. 在服务器向客户返回一个部分响应, 它必须描述响应覆盖的范围和整个实体长度. 一般格式:
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
四, Header 示例
请求下载整个文件:
- 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: 文件总大小
一个最简单的断点续传实现大概如下:
1. 客户端下载一个 1024K 的文件, 已经下载了其中 512K
2. 网络中断, 客户端请求续传, 因此需要在 HTTP 头中申明本次需要续传的片段:
Range:bytes=512000-
这个头通知服务端从文件的 512K 位置开始传输文件
3. 服务端收到断点续传请求, 从文件的 512K 位置开始传输, 并且在 HTTP 头中增加:
Content-Range:bytes 512000-/1024000
并且此时服务端返回的 HTTP 状态码应该是 206, 而不是 200.
但是在实际场景中, 会出现一种情况, 即在终端发起续传请求时, URL 对应的文件内容在服务端已经发生变化, 此时续传的数据肯定是错误的. 如何解决这个问题了? 显然此时我们需要有一个标识文件唯一性的方法. 在 RFC2616 中也有相应的定义, 比如实现 Last-Modified 来标识文件的最后修改时间, 这样即可判断出续传文件时是否已经发生过改动. 同时 RFC2616 中还定义有一个 ETag 的头, 可以使用 ETag 头来放置文件的唯一标识, 比如文件的 MD5 值.
终端在发起续传请求时应该在 HTTP 头中申明 If-Match 或者 If-Modified-Since 字段, 帮助服务端判别文件变化.
另外 RFC2616 中同时定义有一个 If-Range 头, 终端如果在续传是使用 If-Range.If-Range 中的内容可以为最初收到的 ETag 头或者是 Last-Modfied 中的最后修改时候. 服务端在收到续传请求时, 通过 If-Range 中的内容进行校验, 校验一致时返回 206 的续传回应, 不一致时服务端则返回 200 回应, 回应的内容为新的文件的全部数据.
相关参考链接: http://blog.ncmem.com/wordpress/2019/08/09/http断点续传/
来源: http://www.bubuko.com/infodetail-3202883.html