该功能在 HTTP Range规范(RFC7233)中声明
设计三个http状态码:
206 Partial Content:部分返回416 Range Not Satisfied:范围不满足412 Precondition failed:之前的数据已过期
思考实现以下功能:
- 客户端如何下载数据的片段?(断点续传,多线程下载,视频播放器实时拖动)
- 如何检测客户端已下载的部分本地文件是否在服务端发生了改变?
- 客户端一次请求如何同时下载多个片段的数据?
- 服务端如何告知客户端它支持
Range请求
客户端如何下载数据的片段?
通过Range请求头,告知服务端此次请求的字节范围,使用方法如下:
- 请求单片段字节:
Range: bytes=0-499 - 请求多片段字节:
Range: 500-600,601-999,多重范围响应头中Content-Type: multiple/byteranges; boundary=...,响应体中使用boundary分隔 - 仅要第1个和最后1个字节:
Range: 0-0, -1
下载多个片段时的返回数据
发起Range: bytes=0-5,10-15的请求时:
下载多个片段数据时,响应头中会返回Content-Type: multiple/byteranges; boundary=00000000000000006097;
然后响应体如下:
--00000000000000006097Content-Type: text/plain; charset=utf-8Content-Range: bytes 0-5/27abcdef--00000000000000006097Content-Type: text/plain; charset=utf-8Content-Range: bytes 10-15/27klmnop--00000000000000006097--
服务端如何告知客户端它支持Range请求?
通过Accept-Ranges: bytes | none响应头,bytes表示支持,none表示不支持
客户端如何判断已缓存的部分是否过期?
把已响应的响应头中Etag作为下次请求的Is-Match请求头传过去,如果服务端判断数据已过期,则返回
发起 0-5 字节的请求:curl protocol.taohui.tech/app/letter.txt -H 'Range: bytes=0-5' - I拿到响应头中的 Etag再次发起 6-10 字节的请求:curl protocol.taohui.tech/app/letter/txt -H 'Range: bytes=6-10' -H 'If-Match:5cc3f0b5-1b'
验证本地数据未过期,则第二次请求正常返回数据,如本地数据已过期,则返回412 Precondition Failed
Is-Unmodified-Since和Is-MatchIf-Range Etag或者Last-Modified
请求数据不满足
比如数据总共26字节,发起请求Range: bytes=30-50,此时数据不满足,返回状态码416 Range Not Satisfiable
如果服务器不支持Range请求时,则以200返回完整的响应包体
视频分片播放实战
请求接口:https://f.video.weibocdn.com/u0/GjoQbWbAgx07WRNUrpa0010412008N5g0E010.mp4?label=mp4_720p&template=576x1280.24.0&media_id=4780667238809610&tp=8x8A3El:YTkl0eM8&us=0&ori=1&bf=5&ot=v&lp=00001qykEd&ps=mZ6WB&uid=ziYazFH&ab=7397-g1,8012-g2,6377-g0,8013-g0,3601-g28,1258-g0&Expires=1655890856&ssig=Sb%2F%2Bdv8p%2Bq&KID=unistore,video设置请求头:Range: bytes=0-100000
