4.1 消息类型
HTTP 消息包括从客户端到服务器的请求和从服务器到客户端的响应。
HTTP-message = Request | Response ; HTTP/1.1 messages
请求(第 5 节)和响应(第 6 节)消息使用 RFC 822 [9] 的通用消息格式来传输实体(消息的有效载荷)。这两种类型的消息都包括一个起始行、零个或多个头字段(也称为 “头”)、一个表示头字段结束的空行(即 CRLF 前没有任何内容的行),以及可能的消息体。
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
为了稳健起见,服务器应该忽略在预期有 Request-Line 的地方收到的任何空行。换句话说,如果服务器在一个消息的开头读取协议流,并首先收到一个 CRLF,它应该忽略这个 CRLF。
某些有问题的 HTTP/1.0 客户端实现会在 POST 请求后产生额外的 CRLF。为了重申 BNF 明确禁止的内容,HTTP/1.1 客户端不得在请求前或请求后添加额外的 CRLF。
4.2 消息头
HTTP 头字段,包括通用头字段(第 4.5 节)、请求头字段(第 5.3 节)、响应头字段(第 6.2 节)和实体头字段(第 7.1 节),遵循与 RFC 822 第 3.1 节 [9] 中给出的相同的通用格式。每个头字段由一个名称和一个冒号(”:”)以及字段值组成。字段名是不区分大小写的。字段值前面可以有任何数量的 LWS,但最好有一个 SP。头字段可以扩展到多行,在每行前至少有一个 SP 或 HT(horizontal-tab)。在生成 HTTP 结构时,应用程序应该遵循 “通用形式”,如果有已知的或指明的形式,因为可能存在一些不能接受任何超出通用形式的实现。
message-header = field-name ":" [ field-value ]
field-name = token
field-value = *( field-content | LWS )
field-content = <the OCTETs making up the field-value
and consisting of either *TEXT or combinations
of token, separators, and quoted-string>
字段内容不包括任何前导或尾随的 LWS:在字段值的第一个非空白字符之前或在字段值的最后一个非空白字符之后出现的线性空白。在不改变字段值语义的情况下,这种前导或尾随的 LWS 可以被删除。在解释字段值或将消息转发到下游之前,在字段内容之间出现的任何 LWS 都可以用一个 SP 来代替。
接收不同字段名的头字段的顺序并不重要。然而,”良好的做法” 是先发送通用头字段,然后是请求头字段或响应头字段,最后是实体头字段。
具有相同字段名的多个消息头字段可以出现在一条消息中,当且仅当该头字段的整个字段值被定义为逗号分隔的列表 [即,#(value)]。在不改变消息语义的情况下,必须能够将多个头字段合并成一个 “字段名:字段值” 对,方法是将每个后续的字段值附加到第一个字段上,每个字段用逗号分隔。因此,具有相同字段名的头字段的接收顺序对组合字段值的解释很重要,因此代理在转发消息时不得改变这些字段值的顺序。
4.3 消息体
HTTP 消息的消息正文(如果有)用于携带与请求或响应相关联的实体。 仅当应用了传输编码(transfer-coding)时,消息体才与实体不同,如传输编码标头字段所示(第 14.41 节)。
message-body = entity-body | <entity-body encoded as per Transfer-Encoding>
Transfer-Encoding 必须用于指示应用程序应用的任何传输编码,以确保消息的安全和正确传输。Transfer-Encoding 是消息的属性,而不是实体的属性,因此可以由任何应用程序沿请求/响应链添加或删除。(但是,第 3.6 节对何时可以使用某些传输编码进行了限制。)
对于请求和响应来说,消息中何时允许有消息体的规则是不同的。
请求中的消息体的存在是通过在请求的消息头中加入 Content-Length 或 Transfer-Encoding 头域来表示的。如果请求方法的规范(第 5.1.1 节)不允许在请求中发送实体体,那么消息体决不能被包括在请求中。服务器应该读取并转发任何请求中的消息体;如果请求方法不包括对实体体的定义语义,那么在处理请求时,消息体应该被忽略。
对于响应消息,消息是否包含消息体取决于请求方法和响应状态代码(第 6.1.1 节)。所有对 HEAD 请求方法的响应必须不包括消息体,即使实体头字段的存在可能使人认为它们包括。所有 1xx(信息)、204(无内容)和304(未修改)响应必须不包括消息体。所有其他响应都包括一个消息体,尽管它可能是零长度的。
4.4 消息长度
一条消息的传输长度(transfer-length)是出现在消息中的消息体的长度;也就是说,在应用了任何传输编码(transfer-codings)之后。当消息中包含一个消息体时,该消息体的传输长度由下列之一决定(按优先顺序)。
任何 “不得” 包括消息体的响应信息(比如 1xx、204 和 304 响应以及对 HEAD 请求的任何响应)总是由头字段之后的第一个空行结束,不管信息中存在实体头字段。
如果存在一个 Transfer-Encoding 头字段(第 14.41 节),并且有 “identity” 以外的任何值,那么传输长度是通过使用 “chunked” 传输编码(第 3.6 节)来定义的,除非消息是通过关闭连接来终止的。
如果存在一个 Content-Length 头字段(第 14.13 节),它的十进制值在 OCTETs 中代表实体长度和传输长度。如果这两个长度不同(即,如果存在 Transfer-Encoding 头字段),则不得发送 Content-Length 头字段。如果收到的消息既有 Transfer-Encoding 头字段又有 Content-Length 头字段,那么后者必须被忽略。
如果消息使用媒体类型 “multipart/byteranges”,并且没有另外指定传输长度,那么这种自我限制的媒体类型定义了传输长度。除非发送方知道接收方能够理解这种媒体类型,否则不能使用这种媒体类型;HTTP1.1 客户端的请求中出现带有多个字节范围指定符的 Range 头,意味着接收方能够解析 multipart/byteranges 响应。
范围头可能会被一个不理解 multipart/byteranges 的 HTTP1.0 代理转发;在这种情况下,服务器必须使用本节第 1、3 或 5 项中定义的方法来限定消息。
- 由服务器关闭连接。(关闭连接不能用于指示请求正文的结束,因为这将使服务器无法发回响应。)
为了与 HTTP/1.0 应用兼容,包含消息体的 HTTP/1.1 请求必须包括一个有效的 Content-Length 头字段,除非服务器是已知的 HTTP/1.1 标准。如果一个请求包含一个消息体,但没有给出内容长度,如果服务器不能确定消息的长度,它应该响应 400(bad request),或者如果它希望坚持接收一个有效的内容长度,则响应 411(length required)。
所有接收实体的 HTTP/1.1 应用程序必须接受 “chunked” 传输编码(第 3.6 节),从而允许在不能事先确定消息长度时对消息使用这种机制。
消息不得同时包括 Content-Length 头和 non-identity 传输编码。如果消息确实包括一个 non-identity 传输编码,则必须忽略 Content-Length。
当在允许有消息体的消息中给出 Content-Length 时,其字段值必须与消息体中的 OCTET 数量完全一致。HTTP/1.1 用户代理必须在收到和检测到无效的长度时通知用户。
4.5 通用头字段
有几个头字段对请求和响应信息都有普遍的适用性,但并不适用于被传输的实体。这些头字段只适用于正在传输的消息。
general-header = Cache-Control ; Section 14.9
| Connection ; Section 14.10
| Date ; Section 14.18
| Pragma ; Section 14.32
| Trailer ; Section 14.40
| Transfer-Encoding ; Section 14.41
| Upgrade ; Section 14.42
| Via ; Section 14.45
| Warning ; Section 14.46
通用头字段的名称只有在结合协议版本的变化时才能可靠地扩展。然而,如果通信中的所有各方都承认它们是通用头字段,那么新的或试验性的头字段可以被赋予通用头字段的语义。未被识别的头字段被视为实体头字段。