Skip to main content

4. Transfer Codings (传输编码)

传输编码 (Transfer codings) 名称用于指示已经、可以或可能需要应用于有效载荷正文的编码转换, 以确保通过网络"安全传输"。这与内容编码不同, 内容编码是资源的属性; 传输编码是消息的属性, 而不是表示的属性。

transfer-coding    = "chunked" ; Section 4.1
/ "compress" ; Section 4.2.1
/ "deflate" ; Section 4.2.2
/ "gzip" ; Section 4.2.3
/ transfer-extension
transfer-extension = token *( OWS ";" OWS transfer-parameter )

参数采用名称或名称=值对的形式。

transfer-parameter = token BWS "=" BWS ( token / quoted-string )

所有传输编码名称都是不区分大小写的, 并且应该在 HTTP Transfer Coding 注册表中注册, 如 Section 8.4 中定义的那样。它们在 Transfer-Encoding (Section 3.3.1) 和 TE (Section 4.3) 头部字段中使用。

4.1. Chunked Transfer Coding (分块传输编码)

分块传输编码 (chunked transfer coding) 将有效载荷正文包装成一系列块 (chunks), 每个块都有自己的大小指示器, 后跟一个可选的包含尾部字段的尾部区段。分块允许对动态生成的内容进行流式传输, 以及在内容发送过程中传递可能对消息完整性检查有用的元数据。

chunked-body   = *chunk
last-chunk
trailer-part
CRLF

chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
chunk-size = 1*HEXDIG
last-chunk = 1*("0") [ chunk-ext ] CRLF

chunk-data = 1*OCTET ; a sequence of chunk-size octets

块大小 (chunk-size) 字段是一个十六进制数字字符串, 指示块数据的大小 (以八位字节为单位)。分块传输编码在所有块数据发送之后完成, 并用最后一个块 (last-chunk) 表示, 该块是一个块大小为零的块, 后跟尾部 (如果有的话), 并以空行终止。

接收方必须能够解析和解码分块传输编码。

4.1.1. Chunk Extensions (块扩展)

分块传输编码允许每个块包含零个或多个块扩展 (chunk extensions), 紧跟在块大小之后, 目的是向接收方提供每个块的元数据 (例如签名或哈希值)、中间传输的控制信息, 或者有效载荷正文大小的随机化。

chunk-ext      = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )

chunk-ext-name = token
chunk-ext-val = token / quoted-string

分块传输编码对块扩展的使用是可选的。如果接收到块扩展且对于特定接收方不被识别, 则接收方必须忽略未被识别的块扩展。

发送方不应该生成不包含在每个特定块扩展的定义中的块扩展名称或参数, 除非发送方知道接收方期望该扩展。

例如, 可能有一个签名块扩展, 在最后一个块中提供一个签名, 该签名可以由原始编码器生成以提供可验证的端到端完整性检查。接收方如果不理解该扩展, 则会忽略该扩展并使用标准解码来接收有效载荷。

4.1.2. Chunked Trailer Part (分块尾部区段)

尾部 (trailer) 允许发送方在分块消息的末尾包含额外的头部字段以提供元数据, 这些元数据可能在消息正文发送时动态生成, 例如消息完整性检查、数字签名或后处理状态。尾部字段与头部字段相同, 除了它们在分块正文之后而不是在消息的头部区段中发送。

trailer-part   = *( header-field CRLF )

发送方绝对不能在尾部中生成 Transfer-EncodingContent-LengthTrailer 字段。

当接收到包含尾部字段的消息时, 接收方可以处理尾部字段, 也可以丢弃它们。

接收方必须能够解析尾部字段, 因为它们的存在表示应用程序可能依赖于这些字段的语义, 如果应用程序处理消息的话。如果应用程序不知道如何处理尾部字段, 它们应该被忽略。

服务器不应该生成尾部字段, 除非存在以下一个或多个条件为真:

a) 请求包含一个 TE 头部字段值, 其中至少有一个成员是 "trailers" (除了 "trailers" 本身);

b) 服务器是源服务器, 尾部字段由服务器生成, 并且字段被定义为该响应状态码的可选元数据;

c) 尾部字段由服务器生成, 并且只要客户端能够接收并处理尾部字段, 就可以提供对接收方有益处的信息, 例如动态生成的 Content-MD5 或数字签名。

4.1.3. Decoding Chunked (解码分块)

解码分块传输编码的过程可以按如下方式实现 (使用伪代码):

length := 0
read chunk-size, chunk-ext (if any), and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to decoded-body
length := length + chunk-size
read chunk-size, chunk-ext (if any), and CRLF
}
read trailer field
while (trailer field is not empty) {
if (trailer field is allowed to be sent in a trailer) {
append trailer field to existing header fields
}
read trailer-field
}
Content-Length := length
Remove "chunked" from Transfer-Encoding

示例:

一个包含两个块的分块正文示例, 第一个块包含消息 "Hello ", 第二个块包含消息 "World!":

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

6\r\n
Hello \r\n
6\r\n
World!\r\n
0\r\n
\r\n

注意: \r\n 表示 CRLF。

4.2. Compression Codings (压缩编码)

以下三种压缩编码名称是为了与 HTTP/1.0 兼容而定义的。尽管这些内容编码描述可以应用于任何类型的数据, 但它们通常仅应用于 Content-Encoding, 很少应用于 Transfer-Encoding

4.2.1. Compress Coding (Compress 编码)

"compress" 编码是一种自适应 Lempel-Ziv-Welch (LZW) 编码 [Welch], 通常由 UNIX 文件压缩程序 "compress" 产生。接收方应该认为 "x-compress" 等同于 "compress"。

4.2.2. Deflate Coding (Deflate 编码)

"deflate" 编码是一个 "zlib" 数据格式 [RFC1950], 包含一个 "deflate" 压缩数据流 [RFC1951], 该数据流使用 Lempel-Ziv (LZ77) 压缩算法和 Huffman 编码的组合。

注意: 某些非符合实现发送 "deflate" 压缩数据, 而不将其包装在 zlib 数据格式中。

4.2.3. Gzip Coding (Gzip 编码)

"gzip" 编码是一个 LZ77 编码, 具有 32 位循环冗余校验 (CRC), 通常由 gzip 文件压缩程序 [RFC1952] 产生。接收方应该认为 "x-gzip" 等同于 "gzip"。

4.3. TE (TE)

"TE" 头部字段指示除了分块之外, 客户端愿意接受哪些传输编码作为响应的一部分, 以及客户端是否愿意接受尾部字段。

"TE" 字段值由逗号分隔的传输编码列表组成, 每个传输编码都可以包括可选的接受参数 (如 [Section 5.3.1 of RFC7231] 中定义的那样)。

TE        = #t-codings
t-codings = "trailers" / ( transfer-coding [ t-ranking ] )
t-ranking = OWS ";" OWS "q=" rank
rank = ( "0" [ "." 0*3DIGIT ] )
/ ( "1" [ "." 0*3("0") ] )

发送方 TE 头部字段还指示发送方愿意接受尾部字段在分块传输编码中, 通过在其值中包含关键字 "trailers" 来表示。这个关键字是为了支持那些可能不希望在尾部字段中发送某些头部字段的实现, 除非接收方会处理它们。

示例:

TE: deflate
TE:
TE: trailers, deflate;q=0.5

TE 头部字段仅适用于立即连接。因此, 关键字 "TE" 必须作为连接选项提供 (见 Section 6.1) 在任何其他包含 TE 的 HTTP/1.1 消息中。

客户端绝对不能在 TE 头部字段中发送 "chunked" 传输编码名称; 分块总是可接受的用于 HTTP/1.1 接收方。

如果 TE 字段值为空或者不存在 TE 头部字段, 则唯一可接受的传输编码是分块。没有 TE 头部字段的消息暗示客户端将接受分块传输编码, 这总是对于 HTTP/1.1 接收方是可接受的。

由于 TE 头部字段应用于立即连接, 因此发送 TE 的发送方还必须在 Connection 头部字段 (Section 6.1) 中发送 "TE" 连接选项, 以防止 TE 字段被不支持其语义的中间方转发。

4.4. Trailer (Trailer)

当发送方知道有哪些头部字段将在最后一个块的尾部区段中发送时, 发送方应该发送包含这些头部字段名称列表的 Trailer 头部字段。这允许接收方准备接收这些头部字段, 如果它选择处理它们的话。

Trailer = 1#field-name

例如:

Trailer: Expires

发送方绝对不能在 Trailer 字段中列出以下头部字段名称:

  • Transfer-Encoding
  • Content-Length
  • Host
  • 缓存控制头部字段 (例如 Cache-Control, Expires 等), 如 [RFC7234] 的 [Section 5.1] 中所述
  • 认证头部字段 (例如 Authorization, Set-Cookie)
  • 内容编码头部字段 (例如 Content-Encoding, Content-Type)
  • 路由头部字段 (例如 Via)
  • 请求修饰符 (例如控制和条件, 如 [RFC7231] 的 [Section 5] 中所述)

由于 Trailer 的目的是描述将在尾部区段中出现的内容, 以便接收方能够准备好接收这些字段, 它对于代理在转发消息时进行正确操作是有帮助的, 即使接收方可能会丢弃尾部。


📍 翻译进度: Section 4 完成

下一章节: Section 5. Message Routing (消息路由)

请回复 "继续" 以继续翻译下一章节。