14. Range Requests (范围请求)
客户端通常会遇到传输中断或需要仅获取大型表示的一部分的情况。范围请求是一种可选功能,允许客户端仅请求所选表示的一个或多个子范围,而不是整个表示。
范围请求机制在几种不同场景中非常有用:
- 大型文件的部分下载可以被分割到多个并发请求中,从而加快总体检索速度
- 中断的传输可以从中断点恢复,而不是重新开始
- 某些媒体类型允许增量渲染或播放,用户代理可以在接收数据时立即开始处理
服务器不需要支持范围请求。然而,源服务器应该(SHOULD)支持范围请求,因为范围请求可以减少网络使用并改善服务响应性。
14.1. Range Units (范围单位)
表示可以被分成子范围的不同方式。范围单位定义了如何分割表示数据。
range-unit = token
所有范围单位名称都是不区分大小写的,应该在HTTP Range Unit Registry中注册。
14.1.1. Range Specifiers (范围说明符)
范围说明符定义了表示数据的一个或多个子范围。
range-spec = range-unit "=" range-set
range-set = 1#range-spec-value
range-spec-value = int-range / suffix-range / other-range
范围单位允许客户端说明它正在请求哪种类型的范围。
14.1.2. Byte Ranges (字节范围)
"bytes"范围单位是为HTTP定义的,用于表示八位字节序列的子范围(即字节范围)。
byte-ranges-specifier = bytes-unit "=" byte-range-set
byte-range-set = 1#byte-range-spec
byte-range-spec = first-byte-pos "-" [ last-byte-pos ]
/ suffix-byte-range-spec
suffix-byte-range-spec = "-" suffix-length
first-byte-pos = 1*DIGIT
last-byte-pos = 1*DIGIT
suffix-length = 1*DIGIT
bytes-unit = "bytes"
first-byte-pos值给出了范围中第一个字节的字节偏移量。last-byte-pos值给出了范围中最后一个字节的字节偏移量;即,指定的字节位置是包含的。字节偏移量从零开始。
示例:
bytes=0-499表示前500个字节bytes=500-999表示第二个500字节bytes=-500表示最后500个字节bytes=500-表示从字节500开始的所有字节bytes=0-0,-1表示第一个和最后一个字节
14.2. Range
"Range"头部字段用于请求表示数据的一个或多个子范围。
Range = range-unit "=" range-set
服务器可以(MAY)忽略Range头部字段。然而,源服务器和中间缓存应该(SHOULD)在可能的情况下支持字节范围,因为Range支持有效从部分失败的传输中恢复以及大型表示的部分检索。
服务器必须(MUST)忽略在除GET之外的请求方法中接收的Range头部字段。
如果所有前提条件都为真,则支持Range头部字段的源服务器必须(MUST):
- 如果Range头部字段包含它不支持的范围单位,则忽略Range头部字段
- 如果Range头部字段在语法上无效,则返回416(Range Not Satisfiable)状态码
- 如果Range头部字段包含可满足的字节范围集,则返回206(Partial Content)响应,其中包含一个或多个部分表示
示例请求:
GET /document HTTP/1.1
Host: www.example.com
Range: bytes=0-1023
14.3. Accept-Ranges
"Accept-Ranges"头部字段允许服务器指示它支持目标资源的范围请求。
Accept-Ranges = acceptable-ranges
acceptable-ranges = 1#range-unit / "none"
源服务器如果接受给定目标资源的范围请求,应该(SHOULD)发送Accept-Ranges头部字段以指示支持哪些范围单位。客户端可以(MAY)生成范围请求而无需接收此头部字段。
示例:
Accept-Ranges: bytes
Accept-Ranges: none
"none"值表示不接受任何范围单位,意味着服务器不支持该资源的任何范围请求。
14.4. Content-Range
"Content-Range"头部字段在单部分206(Partial Content)响应中发送,以指示所包含的部分表示的字节范围,或在416(Range Not Satisfiable)响应中发送,以提供有关所选表示的信息。
Content-Range = range-unit SP
( range-resp / unsatisfied-range )
range-resp = byte-content-range
/ other-range-resp
byte-content-range = bytes-unit SP
( byte-range-resp / unsatisfied-range )
byte-range-resp = first-byte-pos "-" last-byte-pos
"/" ( complete-length / "*" )
complete-length = 1*DIGIT
unsatisfied-range = "*/" complete-length
other-range-resp = *CHAR
示例:
Content-Range: bytes 0-1023/5000
Content-Range: bytes 1024-2047/5000
Content-Range: bytes */5000
第一个示例表示正在传输完整表示(长度为5000字节)的前1024个字节。第三个示例表示范围请求无法满足,因为所选表示的完整长度为5000字节。
14.5. Partial PUT (部分PUT)
部分PUT请求不是范围请求,但它与范围请求使用相同的机制来描述正在传输的内容。客户端可以通过在PUT请求中包含Content-Range头部字段来发送部分PUT。
然而,部分PUT很少在实践中使用,因为:
- 它要求客户端知道资源的当前状态
- 它容易受到竞态条件的影响
- 大多数源服务器不支持它
因此,客户端不应该(SHOULD NOT)使用部分PUT,除非它确定目标服务器支持它。
14.6. Media Type multipart/byteranges (媒体类型 multipart/byteranges)
当发送多个范围时,服务器应该(SHOULD)使用multipart/byteranges媒体类型。
multipart/byteranges
此媒体类型的每个body部分必须(MUST)包含:
- Content-Type头部字段,指示该body部分中包含的表示的媒体类型
- Content-Range头部字段,指示所包含的范围
示例响应:
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
--THIS_STRING_SEPARATES
Content-Type: text/html
Content-Range: bytes 0-100/1234
[前101字节]
--THIS_STRING_SEPARATES
Content-Type: text/html
Content-Range: bytes 500-999/1234
[第500-999字节]
--THIS_STRING_SEPARATES--
当客户端请求多个不相交的范围时,服务器应该(SHOULD)仅在以下情况下返回多部分响应:
- 范围没有重叠
- 范围的顺序与它们在表示中出现的顺序相同
否则,服务器应该(SHOULD)返回整个表示或合并重叠的范围。