跳到主要内容

7. 传输编码

传输编码名称用于指示一种编码转换, 该转换已经, 可以或可能需要应用于消息的内容, 以确保通过网络进行 "safe transport". 它不同于内容编码 (content coding), 因为传输编码是消息的属性, 而不是正在传输的表示的属性.

所有 transfer-coding 名称都不区分大小写, 并且应注册在 HTTP Transfer Coding registry 中, 如 Section 7.3 所定义. 它们用于 Transfer-Encoding (Section 6.1) 和 TE ([HTTP] 的 Section 10.1.4) 头部字段 (后者还定义了 "transfer-coding" 语法).

7.1. Chunked 传输编码

chunked 传输编码会包装内容, 以便将其作为一系列块 (chunk) 传输, 每个块都有自己的大小指示符, 后面跟随一个 OPTIONAL trailer section, 其中包含 trailer fields. chunked 允许未知大小的内容流作为一系列长度定界的缓冲区传输, 使发送方能够保持连接持久性, 并使接收方知道何时已收到完整消息.

chunked-body   = *chunk
last-chunk
trailer-section
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 字段是一个十六进制数字字符串, 指示 chunk-data 的大小, 单位为八位组. 当收到 chunk-size 为零的块时, chunked 传输编码即完成; 其后可能跟随 trailer section, 最后由空行终止.

接收方 MUST 能够解析和解码 chunked 传输编码.

HTTP/1.1 未定义任何方式来限制 chunked 响应的大小, 以便中间件能够确信可以缓冲整个响应. 此外, 如果接收实现不能准确表示非常大的块大小值, 这些值可能导致溢出或精度损失. 因此, 接收方 MUST 预期可能出现很大的十六进制数, 并防止因整数转换溢出而导致解析错误, 或因整数表示导致精度损失.

chunked 编码不定义任何参数. 参数的出现 SHOULD 被视为错误.

7.1.1. 块扩展

chunked 编码允许每个块在 chunk-size 之后立即包含零个或多个块扩展 (chunk extension), 用于提供每块元数据 (如签名或哈希), 消息中途的控制信息, 或消息体大小随机化.

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

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

chunked 编码特定于每个连接, 并且很可能在任何更高层应用有机会检查扩展之前, 就被每个接收方 (包括中间件) 移除或重新编码. 因此, chunk extension 的使用通常限于专门的 HTTP 服务, 例如 "long polling" (客户端和服务器可以对 chunk extension 的使用有共享预期), 或用于端到端安全连接内的填充.

接收方 MUST 忽略无法识别的 chunk extension. 服务器应将请求中收到的 chunk extension 总长度限制在与所提供服务相称的合理范围内, 就像它对消息其他部分应用长度限制和超时一样; 如果该长度被超过, 则生成适当的 4xx (Client Error) 响应.

7.1.2. Chunked Trailer Section

trailer section 允许发送方在 chunked 消息末尾包含附加字段, 以提供可能在内容发送过程中动态生成的元数据, 例如消息完整性校验, 数字签名或后处理状态. trailer fields 的正确使用和限制在 [HTTP] 的 Section 6.5 中定义.

trailer-section   = *( field-line CRLF )

从消息中移除 chunked 编码的接收方 MAY 选择性保留或丢弃收到的 trailer fields. 保留收到的 trailer field 的接收方 MUST 要么将该 trailer field 与收到的头部字段分开存储/转发, 要么将收到的 trailer field 合并到头部区段中. 除非相应头部字段定义明确允许并说明如何安全合并 trailer field 值, 否则接收方 MUST NOT 将收到的 trailer field 合并到头部区段.

7.1.3. 解码 Chunked

解码 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 content
length := length + chunk-size
read chunk-size, chunk-ext (if any), and CRLF
}
read trailer field
while (trailer field is not empty) {
if (trailer fields are stored/forwarded separately) {
append trailer field to existing trailer fields
}
else if (trailer field is understood and defined as mergeable) {
merge trailer field with existing header fields
}
else {
discard trailer field
}
read trailer field
}
Content-Length := length
Remove "chunked" from Transfer-Encoding

7.2. 用于压缩的传输编码

以下用于压缩的传输编码名称由与其对应内容编码相同的算法定义:

compress (and x-compress) : 参见 [HTTP] 的 Section 8.4.1.1.

deflate : 参见 [HTTP] 的 Section 8.4.1.2.

gzip (and x-gzip) : 参见 [HTTP] 的 Section 8.4.1.3.

压缩编码不定义任何参数. 对于这些压缩编码中的任何一个, 参数的出现 SHOULD 被视为错误.

7.3. 传输编码注册表

"HTTP Transfer Coding Registry" 定义传输编码名称的命名空间. 它维护在 https://www.iana.org/assignments/http-parameters.

注册项 MUST 包含以下字段:

  • Name
  • Description
  • Pointer to specification text

传输编码名称 MUST NOT 与内容编码名称 ([HTTP] 的 Section 8.4.1) 重叠, 除非编码转换完全相同, 如 Section 7.2 中定义的压缩编码就是这种情况.

7.4. 协商传输编码

TE 头部字段 ([HTTP] 的 Section 10.1.4) 用于请求中, 以指示除 chunked 之外客户端愿意在响应中接受哪些传输编码, 以及客户端是否愿意在 chunked 传输编码中保留 trailer fields.

客户端 MUST NOT 在 TE 中发送 chunked 传输编码名称; chunked 对 HTTP/1.1 接收方始终是可接受的.