Skip to main content

2. Message (消息)

HTTP/1.1 客户端和服务器通过发送消息进行通信。有关 HTTP 的通用术语和核心概念,请参见 [HTTP] 的第 3 节。

2.1. Message Format (消息格式)

HTTP/1.1 消息 (message) 由起始行 (start-line) 后跟 CRLF 和一系列八位字节组成,其格式类似于互联网消息格式 [RFC5322]: 零个或多个头字段行 (header field lines) (统称为 "headers" 或 "header section")、一个指示头部分结束的空行,以及一个可选的消息体 (message body)。

HTTP-message   = start-line CRLF
*( field-line CRLF )
CRLF
[ message-body ]

消息可以是从客户端到服务器的请求 (request),也可以是从服务器到客户端的响应 (response)。在语法上,这两种类型的消息仅在起始行上有所不同,起始行可以是请求行 (request-line,用于请求) 或状态行 (status-line,用于响应),以及确定消息体长度的算法 (第 6 节)。

start-line     = request-line / status-line

理论上,客户端可以接收请求,服务器可以接收响应,通过它们不同的起始行格式来区分它们。实际上,服务器实现为只期望请求 (响应被解释为未知或无效的请求方法),客户端实现为只期望响应。

HTTP 使用了一些类似于多用途互联网邮件扩展 (Multipurpose Internet Mail Extensions, MIME) [RFC2045] 的协议元素。有关 HTTP 和 MIME 消息之间的差异,请参见附录 B。

2.2. Message Parsing (消息解析)

解析 HTTP 消息的正常过程是将起始行读入一个结构中,将每个头字段行按字段名读入哈希表中直到遇到空行,然后使用解析的数据确定是否需要消息体。如果已指示消息体,则将其作为流读取,直到读取的八位字节数量等于消息体长度或连接关闭。

接收方必须 (MUST) 将 HTTP 消息解析为采用 US-ASCII [USASCII] 超集编码的八位字节序列。将 HTTP 消息解析为 Unicode 字符流而不考虑特定编码会产生安全漏洞,因为字符串处理库处理包含八位字节 LF (%x0A) 的无效多字节字符序列的方式各不相同。基于字符串的解析器只能在从消息中提取协议元素之后在该元素内安全使用,例如在消息解析已划分各个字段行之后的头字段行值内。

尽管起始行和字段的行终止符是序列 CRLF,但接收方可以 (MAY) 识别单个 LF 作为行终止符并忽略任何前面的 CR。

发送方禁止 (MUST NOT) 在内容之外的任何协议元素中生成裸 CR (即 CR 字符后面没有紧跟 LF)。这种裸 CR 的接收方必须 (MUST) 将该元素视为无效,或者在处理该元素或转发消息之前用 SP 替换每个裸 CR。

较旧的 HTTP/1.0 用户代理实现可能会在 POST 请求之后发送额外的 CRLF,作为一些早期服务器应用程序未能读取未以行结束符终止的消息体内容的变通方法。HTTP/1.1 用户代理禁止 (MUST NOT) 在请求之前或之后添加额外的 CRLF。如果希望用行结束符终止请求消息体,则用户代理必须 (MUST) 将终止的 CRLF 八位字节计为消息体长度的一部分。

为了健壮性,期望接收和解析请求行的服务器应该 (SHOULD) 忽略在请求行之前收到的至少一个空行 (CRLF)。

发送方禁止 (MUST NOT) 在起始行和第一个头字段之间发送空格。

在起始行和第一个头字段之间接收空格的接收方必须 (MUST) 拒绝消息为无效,或者在不进一步处理的情况下消费每个以空格开头的行 (即忽略整行以及任何后续以空格开头的行,直到收到格式正确的头字段或头部分终止)。拒绝或删除无效的以空格开头的行是必要的,以防止下游接收方误解这些行,这些接收方可能容易受到请求走私 (Section 11.2) 或响应拆分 (Section 11.1) 攻击。

当仅侦听 HTTP 请求消息的服务器,或处理从起始行看起来是 HTTP 请求消息的内容时,接收到除上述健壮性例外之外不符合 HTTP-message 语法的八位字节序列,服务器应该 (SHOULD) 以 400 (Bad Request) 响应并关闭连接。

2.3. HTTP Version (HTTP版本)

HTTP 使用 "<major>.<minor>" 编号方案来指示协议的版本。本规范定义版本 "1.1"。[HTTP] 的第 2.5 节规定了 HTTP 版本号的语义。

HTTP/1.x 消息的版本由起始行中的 HTTP-version 字段指示。HTTP-version 是区分大小写的。

HTTP-version  = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %s"HTTP"

当 HTTP/1.1 消息发送到 HTTP/1.0 接收方 [HTTP/1.0] 或版本未知的接收方时,HTTP/1.1 消息的构造使得如果忽略所有较新的功能,它可以被解释为有效的 HTTP/1.0 消息。本规范对某些新功能设置了接收方版本要求,以便符合标准的发送方只会使用兼容的功能,直到它通过配置或接收消息确定接收方支持 HTTP/1.1。

处理 HTTP 消息的中介 (即所有中介,除了充当隧道的中介) 必须 (MUST) 在转发的消息中发送它们自己的 HTTP-version,除非有意降级作为上游问题的变通方法。换句话说,中介不允许盲目转发起始行而不确保该消息中的协议版本与该中介在接收和发送消息方面都符合的版本相匹配。在不重写 HTTP-version 的情况下转发 HTTP 消息可能会导致通信错误,因为下游接收方使用消息发送方的版本来确定哪些功能可以安全地用于以后与该发送方的通信。

如果已知或怀疑客户端错误地实现了 HTTP 规范且无法正确处理更高版本的响应,例如当客户端无法正确解析版本号或当已知中介盲目转发 HTTP-version 即使它不符合协议的给定次要版本时,服务器可以 (MAY) 对 HTTP/1.1 请求发送 HTTP/1.0 响应。这种协议降级不应该 (SHOULD NOT) 执行,除非由特定的客户端属性触发,例如当一个或多个请求头字段 (例如 User-Agent) 唯一匹配已知有错误的客户端发送的值时。