Skip to main content

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):

  1. 如果Range头部字段包含它不支持的范围单位,则忽略Range头部字段
  2. 如果Range头部字段在语法上无效,则返回416(Range Not Satisfiable)状态码
  3. 如果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很少在实践中使用,因为:

  1. 它要求客户端知道资源的当前状态
  2. 它容易受到竞态条件的影响
  3. 大多数源服务器不支持它

因此,客户端不应该(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)仅在以下情况下返回多部分响应:

  1. 范围没有重叠
  2. 范围的顺序与它们在表示中出现的顺序相同

否则,服务器应该(SHOULD)返回整个表示或合并重叠的范围。