跳到主要内容

4. 对范围请求的响应 (Responses to a Range Request)

4.1 206 部分内容 (Partial Content)​

206 (Partial Content) 状态码表示服务器正在通过传输所选表示中与请求的 Range 头字段 (第 3.1 节) 中找到的可满足范围相对应的一个或多个部分, 来成功地满足对目标资源的范围请求.

如果正在传输单个部分, 则生成 206 响应的服务器必须 (MUST) 生成一个 Content-Range 头字段, 描述所封装的是所选表示的哪个范围, 以及由该范围组成的有效载荷. 例如:

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Range: bytes 21010-47021/47022
Content-Length: 26012
Content-Type: image/gif

... 26012 bytes of partial image data ...

如果正在传输多个部分, 则生成 206 响应的服务器必须 (MUST) 生成一个 "multipart/byteranges" 有效载荷 (如附录 A 所定义), 以及一个包含 multipart/byteranges 媒体类型及其必需的 boundary 参数的 Content-Type 头字段. 为了避免与单部分响应混淆, 服务器禁止 (MUST NOT) 在多部分响应的 HTTP 头部区块中生成 Content-Range 头字段 (该字段将改为在每个部分中发送).

在多部分有效载荷中每个主体部分的头部区域内, 服务器必须 (MUST) 生成与该主体部分所封装范围相对应的 Content-Range 头字段. 如果所选表示在 200 (OK) 响应中本应带有 Content-Type 头字段, 则服务器应当 (SHOULD) 在每个主体部分的头部区域内生成相同的 Content-Type 字段. 例如:

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Length: 1741
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 500-999/8000

...the first range...
--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 7000-7999/8000

...the second range
--THIS_STRING_SEPARATES--

当请求了多个范围时, 服务器可以 (MAY) 合并任何相互重叠的范围, 或者被小于发送多个部分的开销的间隙分隔开的范围, 而不管对应的 byte-range-spec 在收到的 Range 头字段中出现的顺序如何. 由于 multipart/byteranges 有效载荷中各部分之间的典型开销约为 80 字节 (取决于所选表示的媒体类型和所选 boundary 参数的长度), 传输许多小的互不相连的部分可能比传输整个所选表示的效率更低.

服务器禁止 (MUST NOT) 对单一范围的请求生成多部分响应, 因为未请求多个部分的客户端可能不支持多部分响应. 但是, 如果请求了多个范围而只有一个范围被认定为可满足, 或者在合并之后只剩下一个范围, 服务器可以 (MAY) 生成只包含单个主体部分的 multipart/byteranges 有效载荷. 无法处理 multipart/byteranges 响应的客户端禁止 (MUST NOT) 生成请求多个范围的请求.

当生成多部分响应有效载荷时, 服务器应当 (SHOULD) 按照对应的 byte-range-spec 在收到的 Range 头字段中出现的顺序发送各部分, 但不包括那些被认定为不可满足或已被合并到其他范围的范围. 收到多部分响应的客户端必须 (MUST) 检查每个主体部分中存在的 Content-Range 头字段, 以确定该主体部分包含的是哪个范围; 客户端不能指望收到的范围与它所请求的相同, 也不能指望顺序与它所请求的相同.

当生成 206 响应时, 如果以下头字段在对同一请求的 200 (OK) 响应中本应被发送, 则服务器除了生成上述必需的头字段之外, 还必须 (MUST) 生成它们: Date, Cache-Control, ETag, Expires, Content-Location 和 Vary.

如果 206 响应是对带有 If-Range 头字段的请求生成的, 则发送方不应 (SHOULD NOT) 生成上述必需字段之外的其他表示头字段, 因为可以认为客户端已经拥有包含这些头字段的先前响应. 否则, 发送方必须 (MUST) 生成在对同一请求的 200 (OK) 响应中本应发送的所有表示头字段.

206 响应默认是可缓存的; 也就是说, 除非有显式的缓存控制指令另有指示 (见 [RFC7234] 第 4.2.2 节).

4.2 Content-Range​

"Content-Range" 头字段在单部分的 206 (Partial Content) 响应中发送, 用于指示封装为消息有效载荷的所选表示的部分范围; 在多部分 206 响应的每个部分中发送, 用于指示每个主体部分内封装的范围; 并在 416 (Range Not Satisfiable) 响应中发送, 用于提供关于所选表示的信息.

Content-Range = byte-content-range / other-content-range

byte-content-range = bytes-unit SP
( byte-range-resp / unsatisfied-range )

byte-range-resp = byte-range "/" ( complete-length / "*" )
byte-range = first-byte-pos "-" last-byte-pos
unsatisfied-range = "*/" complete-length

complete-length = 1*DIGIT

other-content-range = other-range-unit SP other-range-resp
other-range-resp = *CHAR

如果 206 (Partial Content) 响应包含带有接收方所不理解的范围单位 (第 2 节) 的 Content-Range 头字段, 则接收方禁止 (MUST NOT) 尝试将其与已存储的表示重新组合. 收到此类消息的代理应当 (SHOULD) 将其向下游转发.

对于字节范围, 发送方应当 (SHOULD) 指示从中提取该范围的表示的完整长度, 除非完整长度未知或难以确定. 用星号字符 ("*") 代替 complete-length 表示在生成该头字段时表示长度未知.

以下示例说明发送方已知所选表示的完整长度为 1234 字节时的情形:

Content-Range: bytes 42-1233/1234

第二个示例说明完整长度未知时的情形:

Content-Range: bytes 42-1233/*

如果 Content-Range 字段值包含 last-byte-pos 值小于其 first-byte-pos 值的 byte-range-resp, 或者 complete-length 值小于或等于其 last-byte-pos 值, 则该字段值无效. 无效 Content-Range 的接收方禁止 (MUST NOT) 尝试将收到的内容与已存储的表示重新组合.

对字节范围请求生成 416 (Range Not Satisfiable) 响应的服务器应当 (SHOULD) 发送带有 unsatisfied-range 值的 Content-Range 头字段, 如下例所示:

Content-Range: bytes */1234

416 响应中的 complete-length 表示所选表示的当前长度.

Content-Range 头字段对于未显式描述其语义的状态码没有意义. 在本规范中, 只有 206 (Partial Content) 和 416 (Range Not Satisfiable) 状态码描述了 Content-Range 的含义.

以下是所选表示总共包含 1234 字节时 Content-Range 值的示例:

  • 前 500 字节: Content-Range: bytes 0-499/1234

  • 第二个 500 字节: Content-Range: bytes 500-999/1234

  • 除前 500 字节之外的所有字节: Content-Range: bytes 500-1233/1234

  • 最后 500 字节: Content-Range: bytes 734-1233/1234

4.3 组合范围 (Combining Ranges)​

如果连接过早关闭, 或者请求使用了一个或多个 Range 规格, 响应可能只传输表示的一个子范围. 在若干次这样的传输之后, 客户端可能已经收到了同一表示的多个范围. 只有当它们都具有相同的强验证器 (strong validator) ([RFC7232] 第 2.1 节) 时, 这些范围才能被安全地组合.

对同一目标资源的 GET 请求收到了多个部分响应的客户端, 如果这些响应共享相同的强验证器, 则可以 (MAY) 将它们组合成更大的连续范围.

如果最近的响应是不完整的 200 (OK) 响应, 则该响应的头字段用于任何组合后的响应, 并替换匹配的已存储响应的头字段.

如果最近的响应是 206 (Partial Content) 响应, 且至少一个匹配的已存储响应是 200 (OK), 则组合响应的头字段由最近的那个 200 响应的头字段组成. 如果所有匹配的已存储响应都是 206 响应, 则使用头字段最新的那个已存储响应作为组合响应头字段的来源, 但客户端必须 (MUST) 使用新响应中提供的其他头字段 (Content-Range 除外) 来替换已存储响应中对应头字段的所有实例.

组合后的响应消息主体由新响应和每个选定响应中的部分内容范围的并集组成. 如果该并集构成了表示的整个范围, 则客户端必须 (MUST) 将组合后的响应当作完整的 200 (OK) 响应来处理, 包括一个反映完整长度的 Content-Length 头字段. 否则, 客户端必须 (MUST) 将这组连续范围按以下方式之一处理: 如果组合响应是表示的前缀, 则视为不完整的 200 (OK) 响应; 视为包含 multipart/byteranges 主体的单个 206 (Partial Content) 响应; 或者视为多个 206 (Partial Content) 响应, 每个响应含有一个由 Content-Range 头字段指示的连续范围.

4.4 416 范围不可满足 (Range Not Satisfiable)​

416 (Range Not Satisfiable) 状态码表示请求的 Range 头字段 (第 3.1 节) 中没有任何范围与所选资源的当前范围重叠, 或者所请求的范围集合由于范围无效, 或过多的小范围或重叠范围请求而被拒绝.

对于字节范围, 未与当前范围重叠意味着所有 byte-range-spec 值的 first-byte-pos 都大于所选表示的当前长度. 当因字节范围请求而生成此状态码时, 发送方应当 (SHOULD) 生成指定所选表示当前长度的 Content-Range 头字段 (第 4.2 节).

例如:

HTTP/1.1 416 Range Not Satisfiable
Date: Fri, 20 Jan 2012 15:41:54 GMT
Content-Range: bytes */47022

注意: 由于服务器可以自由忽略 Range, 许多实现只会以包含整个所选表示的 200 (OK) 响应来回应. 这部分是因为大多数客户端已准备好接收 200 (OK) 来完成任务 (尽管效率较低), 部分是因为客户端在收到完整表示之前可能不会停止发出无效的部分请求. 因此, 即使在 416 (Range Not Satisfiable) 响应最为恰当的情况下, 客户端也不能指望一定会收到它.