| 互联网工程任务组(IETF) | R. Fielding, 编辑 |
| 请求评注:9112 | Adobe |
| 废止: 7230 | M. Nottingham, 编辑 |
| STD: 99 | Fastly |
| 类别:标准轨道 | J. Reschke, 编辑 |
| ISSN:2070-1721 | greenbytes |
| 2022年6月 |
HTTP/1.1
摘要
超文本传输协议(HTTP)是一种用于分布式、协作型超文本信息系统的无状态应用层协议。本文档规定了 HTTP/1.1 的消息语法、消息解析、连接管理以及相关的安全问题。
本文档废止了 RFC 7230 的部分内容。
本备忘录的状态
这是一个互联网标准轨道文档。
本文档是互联网工程任务组(IETF)的产物。它代表了 IETF 社区的共识。它已接受公开审查并获得互联网工程指导组(IESG)批准发布。有关互联网标准的更多信息,请参见 RFC 7841 的第 2 节.
有关本文档当前状态、任何勘误以及如何提供反馈的信息,可在 https://www.rfc-editor.org/info/rfc9112 获取。
Copyright Notice
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.
This document may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in such materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English.
1. 引言
超文本传输协议(HTTP)是一种无状态的应用层请求/响应协议,使用可扩展的语义和自描述的消息来与基于网络的超文本信息系统进行灵活交互。HTTP/1.1 由下列文档定义:
本文档规定了如何使用 HTTP/1.1 消息语法、分帧和连接管理机制来传达 HTTP 语义。其目标是为 HTTP/1.1 消息解析器和消息转发中间件定义完整的一组要求。
本文档废止了与 HTTP/1.1 消息和连接管理相关的 RFC 7230 的部分内容,变更在 附录 C.3 中进行了总结。RFC 7230 的其他部分已被 "HTTP Semantics" [HTTP] 所废止。
1.1. 需求表示法
1.2. 语法表示法
它还使用了一种列表扩展,该扩展在 第 5.6.1 节 中定义(参见 [HTTP]),允许使用 "#" 操作符对以逗号分隔的列表进行简明定义(类似于 "*" 操作符用于表示重复)。附录 A 展示了将所有列表操作符展开为标准 ABNF 表示的完整语法集合。
约定上,前缀为 "obs-" 的 ABNF 规则表示出于历史原因保留的过时语法规则。
下列核心规则按引用包含,定义见 [RFC5234] 的 附录 B.1:ALPHA(字母)、CR(回车)、CRLF(CR LF)、CTL(控制字符)、DIGIT(十进制 0-9)、DQUOTE(双引号)、HEXDIG(十六进制 0-9/A-F/a-f)、HTAB(水平制表符)、LF(换行)、OCTET(任意 8 位数据序列)、SP(空格)和 VCHAR(任何可见的 [USASCII] 字符)。
下列规则在 [HTTP] 中定义:
BWS = <BWS, see [HTTP], Section 5.6.3> OWS = <OWS, see [HTTP], Section 5.6.3> RWS = <RWS, see [HTTP], Section 5.6.3> absolute-path = <absolute-path, see [HTTP], Section 4.1> field-name = <field-name, see [HTTP], Section 5.1> field-value = <field-value, see [HTTP], Section 5.5> obs-text = <obs-text, see [HTTP], Section 5.6.4> quoted-string = <quoted-string, see [HTTP], Section 5.6.4> token = <token, see [HTTP], Section 5.6.2> transfer-coding = <transfer-coding, see [HTTP], Section 10.1.4>
下列规则在 [URI] 中定义:
absolute-URI = <absolute-URI, see [URI], Section 4.3> authority = <authority, see [URI], Section 3.2> uri-host = <host, see [URI], Section 3.2.2> port = <port, see [URI], Section 3.2.3> query = <query, see [URI], Section 3.4>
2. 消息
2.1. 消息格式
一个 HTTP/1.1 消息由起始行组成,起始行后跟随 CRLF 和一系列与互联网消息格式相似的八位元序列(Internet Message Format):零个或多个首部字段行(统称为“首部”或“首部节”)、一行空行表示首部节结束,以及可选的消息主体。
HTTP-message = start-line CRLF *( field-line CRLF ) CRLF [ message-body ]
消息可以是客户端发往服务器的请求,或者是服务器发往客户端的响应。从语法上看,两类消息仅在起始行上不同:请求使用 request-line,而响应使用 status-line;并且在确定消息主体长度的算法上有所不同(参见 第 6 节)。
理论上,客户端也可能接收请求而服务器也可能接收响应,并可通过不同的起始行格式来区分。但在实践中,服务器通常只期望接收请求(将响应解释为未知或无效的请求方法),而客户端通常只期望接收响应。
HTTP 使用了一些与多用途互联网邮件扩展(MIME)相似的协议元素。有关 HTTP 与 MIME 消息之间的差异,请参见 附录 B。
2.2. 消息解析
解析 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 八位元计入消息主体长度。
为提高健壮性,期望接收并解析 request-line 的服务器 SHOULD 忽略在 request-line 之前接收的至少一行空行(CRLF)。
发送方 MUST NOT 在起始行与第一个首部字段之间发送空白字符。
接收方若在起始行与第一个首部字段之间接收到空白字符,MUST 要么将消息拒绝为无效,要么消费(丢弃)每个以空白开头的行(即忽略整行以及随后的任何以空白开头的行),直到接收到格式正确的首部字段或首部节终止。拒绝或移除无效的以空白开头的行对于防止下游接收方将其误解并受到请求走私(第 11.2 节)或响应分割(第 11.1 节)攻击是必要的。
当仅监听 HTTP 请求消息的服务器,或根据起始行判断应为 HTTP 请求消息的处理器,接收到一串除了上面列出的鲁棒性例外之外不符合 HTTP-message 语法的八位元序列时,服务器 SHOULD 响应 400 (Bad Request) 并关闭连接。
2.3. 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-version),服务器 MAY 向 HTTP/1.1 请求发送 HTTP/1.0 响应。除非由特定客户端属性触发(例如某些请求首部字段值如 User-Agent 唯一匹配已知有问题的客户端发送的值),否则不应执行此类协议降级 SHOULD NOT。
3. 请求行
请求行以一个 method 令牌开始,随后是一个单个空格 (SP)、request-target,再一个单个空格 (SP),并以协议版本结束。
尽管 request-line 的语法规则要求各组件元素之间以单个 SP 八位元分隔,但接收方 MAY 也可以基于以空白分隔的词边界进行解析,且在除 CRLF 终止符之外的情况下,将任何形式的空白视为 SP 分隔符并忽略前导或尾随空白;此类空白可以包括一个或多个下列八位元:SP、HTAB、VT (%x0B)、FF (%x0C) 或 裸 CR。然而,如果消息有多个接收方且每个接收方对鲁棒性的解释各不相同,则宽松解析可能导致请求走私等安全漏洞(参见 第 11.2 节)。
HTTP 对请求行长度没有预置的限制,详见 RFC9110 第 2.3 节。接收比其实现中任何方法都更长的方法的服务器 SHOULD 响应 501 (Not Implemented) 状态码。接收请求目标比其愿意解析的任意 URI 更长的服务器 MUST 响应 414 (URI Too Long) 状态码(参见 RFC9110 第 15.5.15 节)。
实践中对请求行长度存在各种临时性限制。建议(RECOMMENDED)所有 HTTP 发送方和接收方至少支持 8000 八位元的请求行长度。
3.1. 方法
method 令牌表示要在目标资源上执行的请求方法。请求方法区分大小写。
本规范定义的请求方法可在 RFC9110 第 9 节 找到,文中还包含关于 HTTP 方法注册表以及定义新方法时的注意事项。
3.2. 请求目标
request-target 指明要对其应用请求的目标资源。客户端根据其期望的目标 URI 推导出 request-target。根据被请求的方法以及请求是否发送到代理,request-target 有四种不同的格式。
request-target 中不允许出现空白字符。不幸的是,一些用户代理不能正确对超文本引用中的空白进行编码或排除,导致这些不允许的字符作为 request-target 被发送,形成格式错误的 request-line。
接收方对于无效的 request-line SHOULD 响应 400 (Bad Request) 错误,或使用正确编码的 request-target 发出 301 (Moved Permanently) 重定向。接收方 SHOULD NOT 试图自动修正然后在不重定向的情况下处理该请求,因为该无效的 request-line 可能是刻意构造以绕过请求链上的安全过滤器。
客户端 MUST 在所有 HTTP/1.1 请求消息中发送一个 Host 首部字段(参见 Host,以及 RFC9110 第 7.2 节)。如果目标 URI 包含 authority 组成部分,则客户端 MUST 发送与该 authority 组成部分相同的 Host 字段值,排除任何 userinfo 子组件及其 "@" 定界符(参见 RFC9110 第 4.2 节)。如果目标 URI 的 authority 组成部分缺失或未定义,则客户端 MUST 发送一个 Host 首部字段,其字段值为空。
服务器 MUST 对任何缺少 Host 首部字段的 HTTP/1.1 请求消息,以及对任何包含多于一行 Host 首部字段或 Host 字段值无效的请求消息,返回 400 (Bad Request) 状态码。
3.2.1. origin-form
最常见的 request-target 形式是 origin-form。
origin-form = absolute-path [ "?" query ]
当直接向源服务器(origin server)发出请求时(除 CONNECT 或整站 OPTIONS 请求外,如下文所述),客户端 MUST 仅发送目标 URI 的绝对路径和查询组件作为 request-target。如果目标 URI 的路径组件为空,则客户端 MUST 在 origin-form 的 request-target 中发送 "/" 作为路径。同时还要发送一个 Host 首部字段,详见 RFC9110 第 7.2 节。
例如,想要直接从源服务器检索下列资源表示的客户端:
http://www.example.org/where?q=now
将会打开(或重用)到主机 "www.example.org" 的 80 端口的 TCP 连接并发送如下行:
GET /where?q=now HTTP/1.1 Host: www.example.org
随后是请求消息的其余部分。
3.2.2. absolute-form
当向代理发送请求时(除 CONNECT 或整站 OPTIONS 请求外,如下文所述),客户端 MUST 将目标 URI 以 absolute-form 的形式作为 request-target 发送。
代理会被请求在可能的情况下从有效缓存中处理该请求,或者代表客户端对下一个入站代理服务器或 request-target 指示的源服务器发出相同请求。有关此类“转发”消息的要求定义,请参见 RFC9110 第 7.6 节。
一个绝对形式的 request-line 示例为:
GET http://www.example.org/pub/WWW/TheProject.html HTTP/1.1
即使 request-target 为 absolute-form,客户端 MUST 仍应在 HTTP/1.1 请求中发送 Host 首部字段,因为这允许通过可能未实现 Host 的老旧 HTTP/1.0 代理转发 Host 信息。
当代理接收到具有 absolute-form request-target 的请求时,代理 MUST 忽略接收到的 Host 首部字段(如果有),并改为用 request-target 的主机信息替换它。转发此类请求的代理 MUST 基于接收到的 request-target 生成新的 Host 字段值,而不是转发接收的 Host 字段值。
当源服务器接收到具有 absolute-form request-target 的请求时,源服务器 MUST 忽略接收到的 Host 首部字段(如果有),并改为使用 request-target 的主机信息。注意,如果 request-target 没有 authority 组成部分,在这种情况下会发送一个空的 Host 首部字段值。
服务器 MUST 接受请求中的 absolute-form,尽管大多数 HTTP/1.1 客户端只会将 absolute-form 发送给代理。
3.2.4. asterisk-form
request-target 的 asterisk-form 仅用于针对整个服务器的 OPTIONS 请求(参见 RFC9110 第 9.3.7 节)。
asterisk-form = "*"
当客户端希望请求针对整个服务器的 OPTIONS(而不是该服务器的某个具体命名资源)时,客户端 MUST 仅发送 "*" (%x2A) 作为 request-target。例如,
OPTIONS * HTTP/1.1
如果代理接收到具有 absolute-form request-target 的 OPTIONS 请求,且该 URI 的路径为空且无查询组件,则请求链上的最后一个代理在将请求转发给指定的源服务器时 MUST 发送 "*" 作为 request-target。
例如,下列请求
OPTIONS http://www.example.org:8001 HTTP/1.1
将由最后一个代理转发为
OPTIONS * HTTP/1.1 Host: www.example.org:8001
在连接到主机 "www.example.org" 的 8001 端口之后。
3.3. 重建目标 URI
当 request-target 为 absolute-form 时,目标 URI 即为该 request-target。在这种情况下,服务器将把 URI 解析为其通用组件以便进一步评估。
否则,服务器将根据连接上下文及请求消息的各个部分重构目标 URI,以识别目标资源(参见 RFC9110 第 7.1 节):
- 如果服务器配置提供了固定的 URI scheme,或受信任的出站网关提供了 scheme,则在目标 URI 中使用该 scheme。在大规模部署中,这很常见,因为网关服务器会接收客户端的连接上下文并使用它们与入站服务器建立自己的连接。否则,如果请求是通过受保护的连接接收的,则目标 URI 的 scheme 为 "https";否则为 "http"。
- 如果 request-target 为 authority-form,则目标 URI 的 authority 组件就是 request-target。否则,目标 URI 的 authority 组件为 Host 首部字段的字段值。如果不存在 Host 首部字段,或其字段值为空或无效,则目标 URI 的 authority 组件为空。
- 如果 request-target 为 authority-form 或 asterisk-form,则目标 URI 的合并 path 和 query 组件为空。否则,目标 URI 的合并 path 和 query 组件即为 request-target。
- 一旦按上述方法确定了重建的目标 URI 的各组件,就可以通过连接 scheme、"://"、authority 以及合并的路径和查询组件将其重新组合为 absolute-URI 形式。
示例 1:下列通过安全连接接收的消息
GET /pub/WWW/TheProject.html HTTP/1.1 Host: www.example.org
的目标 URI 为
https://www.example.org/pub/WWW/TheProject.html
示例 2:下列通过不安全连接接收的消息
OPTIONS * HTTP/1.1 Host: www.example.org:8080
的目标 URI 为
http://www.example.org:8080
如果目标 URI 的 authority 组件为空且其 URI scheme 要求非空的 authority(例如 "http" 和 "https"),服务器可以拒绝该请求,或确定是否有一个与入站连接上下文一致的配置默认值适用。上下文可能包括连接细节(如地址和端口)、所应用的安全性以及服务器特定配置的本地定义信息。在进一步处理请求之前,空的 authority 会被替换为配置的默认值。
如果在受保护连接的上下文中提供 authority 的默认名称存在任何可能导致用户代理意图的 authority 与默认值不同的情况,则提供默认名称本质上是不安全的。能够从请求上下文中唯一识别出 authority 的服务器 MAY 在没有该风险的情况下使用该身份作为默认值。作为替代,可能更好的做法是将请求重定向到一个安全资源,说明如何获取新的客户端。
注意,重建客户端的目标 URI 只是识别目标资源过程的一半。另一半是确定该目标 URI 是否标识了服务器愿意并能够发送响应的资源,详见 RFC9110 第 7.4 节。
4. 状态行
响应消息的第一行是 status-line,由协议版本、一个空格 (SP)、状态码、另一个空格组成,并以一个用于描述状态码的可选文本短语结束(该短语为 OPTIONAL)。
尽管 status-line 的语法规则要求各组件元素之间以单个 SP 八位元分隔,但接收方 MAY 也可以基于以空白分隔的词边界进行解析,且在除行终止符之外的情况下,将任何形式的空白视为 SP 分隔符并忽略前导或尾随空白;此类空白可以包括一个或多个下列八位元:SP、HTAB、VT (%x0B)、FF (%x0C) 或 裸 CR。然而,如果消息有多个接收方且每个接收方对鲁棒性的解释各不相同,则宽松解析可能导致响应分割等安全漏洞(参见 第 11.1 节)。
status-code 元素是一个三位整数代码,用于描述服务器理解并满足客户端对应请求的尝试结果。接收方在解析并解释响应消息的其余部分时,应依据该状态码对其定义的语义(如果接收方识别该状态码)或依据该状态码所属的类别(如果具体代码未被识别)来进行处理。
status-code = 3DIGIT
HTTP 的核心状态码定义于 RFC9110 第 15 节,其中包含状态码类别、定义新状态码时的注意事项以及用于收集此类定义的 IANA 注册表。
reason-phrase 的存在仅用于为数值状态码提供文本描述,主要是为了向早期更常与交互式文本客户端一起使用的 Internet 应用协议致敬。
reason-phrase = 1*( HTAB / SP / VCHAR / obs-text )
客户端 SHOULD 忽略 reason-phrase 的内容,因为它不是可靠的信息通道(可能会针对特定语言环境被翻译、被中间件覆盖,或在通过其它版本的 HTTP 转发消息时被丢弃)。服务器 MUST 在状态码与 reason-phrase 之间发送分隔空格,即使 reason-phrase 缺失(即 status-line 将以该空格结尾)。
5. 字段语法
每一行字段由不区分大小写的字段名、冒号 (":")、可选的前导空白、字段行值以及可选的尾随空白组成。
field-line = field-name ":" OWS field-value OWS
在字段值内部的解析规则定义于 RFC9110 第 5.5 节。本节涵盖了在 HTTP/1.1 消息中包含与提取首部字段的一般语法。
5.1. 字段行解析
消息使用通用算法解析,与具体字段名无关。给定字段行值内的内容直到消息字段节整个处理完成后的后续阶段才会被解析(通常在此之后进行)。
字段名与冒号之间不允许出现空白。过去对此类空白处理的差异导致了请求路由和响应处理方面的安全漏洞。服务器 MUST 对任何在头字段名与冒号之间包含空白的接收请求消息以 400 (Bad Request) 状态码拒绝。代理 MUST 在转发响应消息到下游之前移除任何此类空白。
字段行值可以被可选空白(OWS)包围;在人类可读性方面,字段行值前置一个单个 SP 更为首选。字段行值不包括这些前导或尾随空白:在从字段行中提取字段行值时,位于字段行值第一个非空白八位元之前或最后一个非空白八位元之后的 OWS 将由解析器排除。
5.2. 过时的行折叠
历史上,HTTP/1.x 字段值可以通过在每个额外行之前加入至少一个空格或水平制表符(obs-fold)来扩展到多行。本规范弃用此类行折叠,除非在 "message/http" 媒体类型内(参见 第 10.1 节)。
发送方 MUST NOT 生成包含行折叠的消息(即任何字段行值包含与 obs-fold 规则匹配的情况),除非该消息打算被封装在 "message/http" 媒体类型内。
服务器在接收到非 "message/http" 容器内的请求消息中出现 obs-fold 时,MUST 要么以 400 (Bad Request) 拒绝该消息(优先附带说明过时行折叠不可接受的表示),要么在解释字段值或将消息转发到下游之前,将每个接收到的 obs-fold 替换为一个或多个 SP 八位元。
代理或网关在接收到非 "message/http" 容器内的响应消息中出现 obs-fold 时,MUST 要么丢弃该消息并以 502 (Bad Gateway) 替代(优先附带说明收到不可接受的行折叠的表示),要么在解释字段值或将消息转发到下游之前,将每个接收到的 obs-fold 替换为一个或多个 SP 八位元。
6. 消息主体
HTTP/1.1 消息的消息主体(如果存在)用于承载请求或响应的内容(参见 Section 6.4 of [HTTP])。除非已应用传输编码(如 Section 6.1 所述),消息主体与内容是相同的。
message-body = *OCTET
确定 HTTP/1.1 消息中是否存在消息主体的规则在请求和响应之间有所不同。
请求中是否包含消息主体由 Content-Length 或 Transfer-Encoding 首部字段指示。请求消息的分帧与方法语义无关。
响应中消息主体的存在(如 Section 6.3 所述)取决于其所对应的请求方法以及响应状态码。这与 HTTP 语义允许何时包含响应内容相对应(参见 Section 6.4.1 of [HTTP])。
6.1. Transfer-Encoding
Transfer-Encoding 首部字段列出与为形成消息主体而已应用(或将要应用)于内容的一系列传输编码相对应的传输编码名称。传输编码在 Section 7 中定义。
Transfer-Encoding = #transfer-coding ; defined in [HTTP], Section 10.1.4
Transfer-Encoding 类似于 MIME 的 Content-Transfer-Encoding 字段(其用于在 7 位传输服务上安全传输二进制数据),但安全传输对于 8bit-清洁传输协议而言有不同侧重点。在 HTTP 中,Transfer-Encoding 主要用于在内容大小未知的情况下准确界定动态生成的内容。它也用于区分仅在传输过程中应用的编码与选定表示所固有的编码。
接收方 MUST 能够解析 chunked 传输编码(参见 Section 7.1),因为当内容大小事先未知时,它在消息分帧中起着关键作用。发送方 MUST NOT 对同一消息体重复应用 chunked 传输编码(即不得对已分块的消息再分块)。如果对请求的内容应用了除 chunked 之外的任何传输编码,发送方 MUST 将 chunked 作为最终的传输编码以确保消息正确分帧。如果对响应的内容应用了除 chunked 之外的任何传输编码,发送方 MUST 要么将 chunked 作为最终传输编码应用,要么通过关闭连接来终止消息。
例如,
Transfer-Encoding: gzip, chunked
表示内容先使用 gzip 编码压缩,然后在形成消息主体时再使用 chunked 分块编码。
与 Content-Encoding(参见 Section 8.4.1 of [HTTP])不同,Transfer-Encoding 是消息的属性,而不是表示的属性。请求/响应链上的任何接收方 MAY 解码所接收的传输编码或对消息主体应用额外的传输编码,前提是相应地更改 Transfer-Encoding 字段值。有关编码参数的附加信息可以由本规范未定义的其他首部字段提供。
Transfer-Encoding MAY 在对 HEAD 请求的响应中发送,或在对 GET 请求的 304 (Not Modified) 响应中发送(参见 Section 15.4.5 of [HTTP]),尽管这些响应不包含消息主体,用以指示如果请求为无条件的 GET,源服务器本会对消息主体应用传输编码。但该指示并非必需,因为响应链上的任何接收方(包括源服务器)都可以在不需要时移除传输编码。
服务器 MUST NOT 在任何状态码为 1xx (Informational) 或 204 (No Content) 的响应中发送 Transfer-Encoding 首部字段。服务器 MUST NOT 在对 CONNECT 请求的任何 2xx (Successful) 响应中发送 Transfer-Encoding 首部字段(参见 Section 9.3.6 of [HTTP])。
接收含有其不理解的传输编码的请求消息的服务器 SHOULD 响应 501 (Not Implemented)。
Transfer-Encoding 是在 HTTP/1.1 中加入的。一般假定仅声明支持 HTTP/1.0 的实现将无法理解如何处理传输编码的内容,并且收到包含 Transfer-Encoding 的 HTTP/1.0 消息很可能是在传输过程中被转发而未正确处理 chunked 编码。
客户端 MUST NOT 发送包含 Transfer-Encoding 的请求,除非其知道服务器会处理 HTTP/1.1 请求(或更高次版本);这种知识可以来自特定用户配置或记住先前收到响应的版本。服务器 MUST NOT 发送包含 Transfer-Encoding 的响应,除非相应的请求表明了 HTTP/1.1(或更高次版本)。
早期 Transfer-Encoding 的实现有时会同时发送用于消息分帧的 chunked 编码和用于进度条的估计 Content-Length 首部字段。因此 Transfer-Encoding 被定义为覆盖 Content-Length,而不是两者互斥。不幸的是,如果任何下游接收方未按本规范解析消息(尤其是仅实现 HTTP/1.0 的下游接收方),转发此类消息可能导致关于请求走私或响应分割的漏洞。
服务器 MAY 拒绝包含 Content-Length 和 Transfer-Encoding 的请求,或仅根据 Transfer-Encoding 来处理该请求。无论采取何种处理,服务器 MUST 在响应此类请求后关闭连接以避免潜在攻击。
接收包含 Transfer-Encoding 首部字段的 HTTP/1.0 消息的服务器或客户端 MUST 将该消息视为分帧有误,即使存在 Content-Length,也应在处理完消息后关闭连接。消息发送方可能在缓冲中保留了消息的一部分,后续对连接的使用可能导致该部分被误解。
6.2. Content-Length
当消息未包含 Transfer-Encoding 首部字段时,Content-Length 首部字段(参见 Section 8.6 of [HTTP])可提供预期的大小,以十进制八位元数表示,用于潜在内容的长度。对于包含内容的消息,Content-Length 字段值提供了确定数据(和消息)结束位置所需的分帧信息。对于不包含内容的消息,Content-Length 指示所选择表示的大小(参见 Section 8.6 of [HTTP])。
发送方 MUST NOT 在任何包含 Transfer-Encoding 首部字段的消息中发送 Content-Length 首部字段。
6.3. 消息主体长度
消息主体的长度由下列规则之一决定(按优先级顺序):
-
对任何 HEAD 请求的响应以及任何状态码为 1xx (Informational)、204 (No Content) 或 304 (Not Modified) 的响应,总是在首部字段之后的第一个空行处终止,不论消息中存在何种首部字段,因此这些响应不能包含消息主体或尾部节。
-
对 CONNECT 请求的任何 2xx (Successful) 响应意味着在结束首部字段的空行之后连接将立即成为隧道。客户端 MUST 忽略此类消息中接收到的任何 Content-Length 或 Transfer-Encoding 首部字段。
-
如果收到的消息同时具有 Transfer-Encoding 和 Content-Length 首部字段,则 Transfer-Encoding 覆盖 Content-Length。此类消息可能表示试图执行请求走私(参见 Section 11.2)或响应分割(参见 Section 11.1),应被视为错误。选择转发该消息的中间件 MUST 在将消息转发下游之前,先移除接收到的 Content-Length 字段并处理 Transfer-Encoding(如下面所述)。
-
如果存在 Transfer-Encoding 首部字段且 chunked 传输编码(参见 Section 7.1)是最终编码,则消息主体长度由读取并解码分块数据直到传输编码表明数据已完整为止来确定。
如果在响应中存在 Transfer-Encoding 首部字段且 chunked 传输编码并非最终编码,则消息主体长度由读取直到服务器关闭连接来确定。
如果在请求中存在 Transfer-Encoding 首部字段且 chunked 传输编码并非最终编码,则消息主体长度无法可靠确定;服务器 MUST 响应 400 (Bad Request) 并随后关闭连接。
-
如果收到的消息没有 Transfer-Encoding 且包含无效的 Content-Length 首部字段,则消息分帧无效且接收方 MUST 将其视为不可恢复的错误,除非该字段值可以被成功解析为以逗号分隔的列表(参见 Section 5.6.1 of [HTTP]),且列表中的所有值均有效且相同(在这种情况下,消息按该单一值作为 Content-Length 字段值来处理)。如果不可恢复的错误出现在请求消息中,服务器 MUST 响应 400 (Bad Request) 并随后关闭连接。如果出现在代理接收到的响应消息中,代理 MUST 关闭与服务器的连接,丢弃接收到的响应,并向客户端发送 502 (Bad Gateway) 响应。如果出现在用户代理接收到的响应消息中,用户代理 MUST 关闭与服务器的连接并丢弃接收到的响应。
-
如果存在有效的 Content-Length 首部字段且不存在 Transfer-Encoding,其十进制值定义了预期的消息主体长度(以八位元计)。如果发送方在指示的八位元数接收完之前关闭连接或接收方超时,则接收方 MUST 视该消息为不完整并关闭连接。
-
如果这是请求消息且以上情况都不成立,则消息主体长度为零(不存在消息主体)。
-
否则,这是一个未声明主体长度的响应消息,因此消息主体长度由服务器关闭连接之前接收到的八位元数来确定。
由于无法区分成功完成的、以关闭连接作为界定的响应消息与因网络故障而部分接收的消息,服务器 SHOULD 在可能的情况下生成编码或长度限定的消息。关闭界定的特性主要为向后兼容 HTTP/1.0 而保留。
服务器 MAY 拒绝包含消息主体但未包含 Content-Length 的请求,响应 411 (Length Required)。
除非已应用除 chunked 之外的传输编码,发送包含消息主体的请求的客户端 SHOULD 在已知消息主体长度时使用有效的 Content-Length 首部字段,而不是使用 chunked 传输编码,因为某些现有服务即使理解 chunked 也会对 chunked 响应 411 (Length Required) 状态码。这通常是因为这些服务通过一个需要事先知道内容长度的网关实现,而服务器无法或不愿在处理之前缓存整个请求。
发送包含消息主体的请求的用户代理 MUST 发送有效的 Content-Length 首部字段或使用 chunked 传输编码。客户端 MUST NOT 使用 chunked 传输编码,除非它知道服务器将处理 HTTP/1.1(或更高)请求;这种知识可以来自特定用户配置或记住先前收到响应的版本。
如果某连接上最后一个请求的最终响应已完全接收但仍有额外数据可读,用户代理 MAY 丢弃剩余数据或尝试确定该数据是否属于之前的消息主体(这可能发生在之前消息的 Content-Length 值不正确的情况下)。客户端 MUST NOT 将此类额外数据作为单独响应来处理、缓存或转发,因为这种行为会使缓存中毒变得可能。
7. 传输编码
传输编码名称用于指示已、可或可能需要对消息内容应用的编码转换,以确保通过网络的“安全传输”。这不同于内容编码,因为传输编码是消息的属性,而不是被传输表示的属性。
所有传输编码名称均不区分大小写,应在 HTTP 传输编码注册表中注册,如 Section 7.3 所定义。它们用于 Transfer-Encoding(Section 6.1)和 TE(Section 10.1.4 of [HTTP])首部字段中(后者还定义了 "transfer-coding" 语法)。
7.1. 分块传输编码
分块传输编码将内容封装为一系列分块,每个分块有自己的大小指示符,随后可选一个包含尾部字段的尾部节。分块使得未知大小的内容流可以作为一系列长度限定的缓冲区被传输,从而使发送方能够保持连接持久性,接收方也能知道何时已接收完整消息。
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 为零的分块(可能后跟一个尾部节)并最终以空行终止时,分块传输编码完成。
接收方 MUST 能够解析并解码分块传输编码。
HTTP/1.1 未定义任何手段来限制分块响应的大小以便中间件能确保证明其能缓冲整个响应。此外,非常大的分块大小如果在接收实现中不能被准确表示,可能导致溢出或精度丢失。因此,接收方 MUST 预期可能出现大的十六进制数值,并防止因整数转换溢出或整数表示精度损失而导致的解析错误。
分块编码不定义任何参数。其存在参数时 SHOULD 被视为错误。
7.1.1. 分块扩展
分块编码允许每个分块在 chunk-size 之后包含零个或多个分块扩展,用于提供每块的元数据(如签名或哈希)、消息中间控制信息,或用于使消息主体大小随机化。
chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token / quoted-string
分块编码是特定于每个连接的,并且在到达更高层应用检查扩展之前,很可能被每个接收方(包括中间件)移除或重新编码。因此,分块扩展的使用通常仅限于诸如“长轮询”等专用 HTTP 服务(在那里客户端和服务器可以对分块扩展的使用有共享预期),或在端到端安全连接内用于填充。
接收方 MUST 忽略无法识别的分块扩展。服务器应限制在请求中接收的分块扩展的总长度至与所提供服务相称的合理数量,类似于对消息其他部分应用长度限制和超时;如果超过该数量,应生成适当的 4xx (Client Error) 响应。
7.1.2. 分块尾部节
尾部节允许发送方在分块消息末尾包含附加字段,以便提供在发送内容时可能动态生成的元数据,例如消息完整性校验、数字签名或后处理状态。尾部字段的正确使用和限制在 Section 6.5 of [HTTP] 中定义。
trailer-section = *( field-line CRLF )
去除分块编码的接收方 MAY 有选择地保留或丢弃接收到的尾部字段。保留接收到的尾部字段的接收方 MUST 要么将尾部字段单独存储/转发,要么将接收到的尾部字段合并到首部节中。除非相应的首部字段定义明确允许并指示如何安全地合并尾部字段值,接收方 MUST NOT 将接收到的尾部字段合并到首部节中。
7.1.3. 解码分块
分块传输编码的解码过程可用伪代码表示为:
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)
- 参见 Section 8.4.1.1 of [HTTP]。
- deflate
- 参见 Section 8.4.1.2 of [HTTP]。
- gzip (and x-gzip)
- 参见 Section 8.4.1.3 of [HTTP]。
这些压缩编码不定义任何参数。出现参数时 SHOULD 将其视为错误。
7.3. 传输编码注册表
“HTTP 传输编码注册表”定义了传输编码名称的命名空间。其维护地址为 https://www.iana.org/assignments/http-parameters。
注册 MUST 包含下列字段:
- Name
- Description
- Pointer to specification text
传输编码的名称 MUST NOT 与内容编码的名称重叠(参见 Section 8.4.1 of [HTTP]),除非编码转换是相同的情况(如第 7.2 节 中定义的压缩编码)。
TE 首部字段(参见 Section 10.1.4 of [HTTP])在可接受多个传输编码时使用名为 "q" 的伪参数作为排序值。未来对传输编码的注册 SHOULD NOT 定义名为 "q"(不区分大小写)的参数以避免歧义。
添加到该命名空间的值需要 IETF 审查(参见 RFC8126 第 4.8 节)并且 MUST 符合本规范中对传输编码目的的定义。
不鼓励并且不宜在将来使用程序名来标识编码格式。
7.4. 传输编码协商
TE 字段(参见 Section 10.1.4 of [HTTP])在 HTTP/1.1 中用于指示客户端在响应中愿意接受除 chunked 之外的哪些传输编码,以及客户端是否愿意保留分块传输编码中的尾部字段。
客户端 MUST NOT 在 TE 中发送 chunked 传输编码名称;chunked 对 HTTP/1.1 接收方始终是可接受的。
下面给出三个 TE 使用示例。
TE: deflate TE: TE: trailers, deflate;q=0.5
当多个传输编码可接受时,客户端 MAY 使用不区分大小写的 "q" 参数按偏好对编码进行排序(类似于内容协商字段中使用的 q 值;参见 Section 12.4.2 of [HTTP])。排序值为 0 到 1 范围内的实数,0.001 为最低偏好,1 为最高偏好;值为 0 表示“不可接受”。
如果 TE 字段值为空或不存在 TE 字段,则唯一可接受的传输编码是 chunked。无传输编码的消息始终是可接受的。
关键字 "trailers" 指示发送方不会丢弃尾部字段,如 Section 6.5 所述。
由于 TE 首部字段仅适用于即时连接,发送 TE 的发送方 MUST 还应在 Connection 首部字段中发送一个 "TE" 连接选项(参见 Section 7.6.1 of [HTTP]),以防止不支持其语义的中间件转发 TE 首部字段。
8. 处理不完整消息
服务器在收到不完整的请求消息(通常由于请求被取消或触发了超时异常)时,MAY 在关闭连接之前发送错误响应。
客户端在接收到不完整的响应消息时(例如连接被过早关闭或在解码看似分块的传输编码时失败),MUST 将该消息记录为不完整。关于不完整响应的缓存要求定义于 Section 3.3 of [CACHING]。
如果响应在首部节中途终止(在接收到空行之前),并且状态码可能依赖首部字段来传达响应的完整含义,则客户端不能假定该含义已被传达;客户端可能需要重复该请求以确定下一步应采取的操作。
使用分块传输编码的消息主体若未收到终止该编码的零长度分块,则视为不完整。使用有效 Content-Length 的消息若接收的消息主体大小(以八位元计)小于 Content-Length 给出的值,则视为不完整。既无分块传输编码也无 Content-Length 的响应由连接关闭终止,并且如果首部节已完整接收,则被视为完整,除非底层连接表明了错误(例如 TLS 中的“incomplete close”会使响应不完整,如 Section 9.8 所述)。
9. 连接管理
HTTP 消息独立于底层传输层或会话层连接协议。HTTP 仅假定可靠的传输且请求按序到达并且对应的响应也按序到达。将 HTTP 请求和响应结构映射到底层传输协议的数据单元超出本规范范围。
正如 Section 7.3 of [HTTP] 所述,用于 HTTP 交互的具体连接协议由客户端配置和 target URI 决定。例如,"http" URI 方案(Section 4.2.1 of [HTTP])表示默认使用基于 IP 的 TCP 连接,默认 TCP 端口为 80,但客户端可能被配置通过某个代理使用其他连接、端口或协议。
HTTP 实现应执行连接管理,包括维护当前连接的状态、建立新连接或重用现有连接、处理在连接上接收到的消息、检测连接失败以及关闭每个连接。大多数客户端会并行维护多个连接,包括对每个服务器端点的多个连接。大多数服务器设计为维护成千上万的并发连接,同时控制请求队列以实现公平使用并检测拒绝服务攻击。
9.1. 建立
描述如何通过各种传输或会话层协议建立连接超出本规范范围。每个 HTTP 连接映射到一个底层传输连接。
9.2. 将响应与请求关联
HTTP/1.1 未包含用于将给定请求消息与其对应的一个或多个响应消息关联的请求标识符。因此,它依赖响应到达的顺序与在同一连接上发出的请求顺序完全对应。每个请求可能对应多于一个响应,只有当一个或多个信息性响应(1xx; 参见 Section 15.2 of [HTTP])在对同一请求的最终响应之前出现时才会发生。
在连接上有多个未完成请求的客户端 MUST 按发送顺序维护未完成请求的列表,并且 MUST 将该连接上接收到的每个响应消息关联到第一个尚未收到最终(非 1xx)响应的未完成请求。
如果客户端在没有未完成请求的连接上接收到数据,客户端 MUST NOT 将该数据视为有效响应;客户端 SHOULD 关闭连接,因为消息定界现在变得模糊,除非该数据仅由一个或多个 CRLF 组成(可根据 Section 2.2 丢弃)。
9.3. 持久性
HTTP/1.1 默认使用 持久连接,允许在单个连接上承载多个请求和响应。HTTP 实现 SHOULD 支持持久连接。
接收方是否认为连接为持久连接取决于所接收的最近一条消息的协议版本和 Connection 首部字段(参见 Section 7.6.1 of [HTTP]):
- 如果存在 "close" 连接选项(见 Section 9.6),则当前响应后连接不会保持持久;否则,
- 如果接收到的协议是 HTTP/1.1(或更高),则当前响应后连接保持持久;否则,
- 如果接收到的协议是 HTTP/1.0,且存在 "keep-alive" 连接选项,且接收方不是代理或该消息是响应,并且接收方希望遵守 HTTP/1.0 的 "keep-alive" 机制,则当前响应后连接保持持久;否则,
- 连接将在当前响应后关闭。
不支持 持久连接 的服务器 MUST 在每个非 1xx (Informational) 状态码的响应消息中发送 "close" 连接选项。
客户端 MAY 在持久连接上发送额外请求,直到它发送或接收到 "close" 连接选项或接收到不带 "keep-alive" 连接选项的 HTTP/1.0 响应。
为保持持久性,连接上的所有消息需要具有自我定义的消息长度(即非通过关闭连接来界定的长度),如 第 6 节 所述。服务器 MUST 读取完整的请求消息主体,或在发送响应后关闭连接;否则,持久连接上的剩余数据可能被误解为下一个请求。同样,若客户端打算重用连接发送后续请求,则客户端 MUST 读取完整的响应消息主体。
代理服务器 MUST NOT 与 HTTP/1.0 客户端保持持久连接(关于许多 HTTP/1.0 客户端实现的 Keep-Alive 首部字段存在的问题及信息,请参见 附录 C.2.2)。
有关与 HTTP/1.0 客户端向后兼容的更多信息,请参见 附录 C.2.2。
9.3.1. 重试请求
连接可以在任何时候被关闭,可能是有意也可能是无意。实现应预期需要从异步关闭事件中恢复。客户端自动重试一系列未完成请求的条件定义于 Section 9.2.2 of [HTTP]。
9.3.2. 管道化
支持持久连接的客户端 MAY 对其请求进行 管道化(即在不等待每个响应的情况下发送多个请求)。若一系列管道化的请求全部使用安全方法(参见 Section 9.2.1 of [HTTP]),服务器 MAY 并行处理这些请求,但 MUST 以接收请求的相同顺序发送相应的响应。
对请求进行管道化的客户端 SHOULD 在连接在接收所有相应响应之前关闭时重试未得到响应的请求。在失败连接(即服务器在其最后完整响应中未明确关闭连接的情况下导致的连接失败)之后重试管道化请求时,客户端 MUST NOT 在重新建立连接后立即进行管道化,因为先前管道中的第一个未完成请求可能已导致错误响应,如果在过早关闭的连接上再次发送多个请求,该错误响应可能再次丢失(参见 Section 9.6 中描述的 TCP 重置问题)。
幂等方法(参见 Section 9.2.2 of [HTTP])对于管道化很重要,因为它们在连接失败后可以被自动重试。用户代理 SHOULD NOT 在非幂等方法之后进行管道化,直到该方法的最终响应状态码已收到,除非用户代理具有检测并从涉及该管道化序列的部分失败条件中恢复的手段。
接收管道化请求的中间件 MAY 在转发入站请求时对这些请求进行管道化,因为它可以依赖出站用户代理来决定哪些请求可以安全地管道化。如果入站连接在收到响应之前失败,管道化中间件 MAY 尝试重试尚未收到响应的一系列请求(如果这些请求都使用幂等方法);否则,管道化中间件 SHOULD 转发已接收的任何响应然后关闭相应的出站连接,以便出站用户代理可以相应地恢复。
9.4. 并发
客户端应限制其对同一服务器维持的同时打开连接数。
HTTP 的早期修订给出了具体的连接上限,但事实证明对许多应用不切实际。因此,本规范不强制规定特定的最大连接数,而是鼓励客户端在打开多连接时保持谨慎。
通常使用多个连接以避免“队头阻塞”问题,即某个请求需要大量服务器端处理或传输非常大的内容会阻塞同一连接上的后续请求。然而,每个连接都会消耗服务器资源。
此外,在拥塞网络中使用多个连接可能产生不良副作用。在非拥塞网络中使用更多连接也可能产生副作用,因为它们的整体且初始同步的发送行为可能导致原本不会出现的拥塞。
请注意,服务器可能会拒绝其认为滥用或具有拒绝服务攻击特征的流量,例如来自单一客户端的过多打开连接。
9.5. 失败与超时
服务器通常会设置某个超时值,超过该值将不再维持空闲连接。代理服务器可能将该值设得更高,因为客户端可能通过同一代理服务器发起更多连接。持久连接的使用并不对客户端或服务器的该超时长度(或存在与否)施加要求。
希望超时的客户端或服务器 SHOULD 对连接执行优雅关闭。实现 SHOULD 不断监测打开的连接是否收到了关闭信号并相应地处理,因为及时关闭连接的双方有助于回收已分配的系统资源。
客户端、服务器或代理 MAY 在任何时候关闭传输连接。例如,客户端可能在服务器决定关闭“空闲”连接的同时开始发送新请求。从服务器角度看,连接是在空闲时被关闭;但从客户端角度看,请求正在进行中。
服务器 SHOULD 在可能的情况下维持持久连接,并允许底层传输的流量控制机制来解决临时超载,而不是终止连接并期望客户端重试。后者技术可能会加剧网络拥塞或服务器负载。
发送消息主体的客户端 SHOULD 在传输请求时监测网络连接以便检测错误响应。如果客户端看到响应表示服务器不希望接收消息主体并正在关闭连接,则客户端 SHOULD 立即停止传输主体并关闭其一侧的连接。
9.6. 终止
"close" 连接选项被定义为发送方将在响应完成后关闭该连接的信号。当发送方打算关闭连接时,SHOULD 发送包含 "close" 连接选项的 Connection 首部字段(参见 Section 7.6.1 of [HTTP])。例如,
Connection: close
作为请求首部字段表示这是客户端将在该连接上发送的最后一个请求;而作为响应时,同样的字段表示服务器在响应消息完成后将关闭该连接。
注意字段名 "Close" 是保留的,因为将该名称用作首部字段可能与 "close" 连接选项冲突。
发送了 "close" 连接选项的客户端 MUST NOT 在该连接上发送该包含 "close" 的请求之后的进一步请求,并且 MUST 在读取到与该请求对应的最终响应消息后关闭连接。
接收包含 "close" 连接选项的服务器 MUST 在向包含 "close" 连接选项的请求发送最终响应后启动连接关闭(见下文)。服务器 SHOULD 在该连接上的最终响应中发送 "close" 连接选项。服务器 MUST NOT 处理在该连接上随后接收到的任何请求。
发送 "close" 连接选项的服务器 MUST 在发送包含 "close" 连接选项的响应后启动连接关闭(见下文)。服务器 MUST NOT 处理在该连接上随后接收到的任何请求。
接收 "close" 连接选项的客户端 MUST 停止在该连接上发送请求,并在读取包含 "close" 连接选项的响应消息后关闭连接;如果该连接上已经发送了额外的管道化请求,客户端 SHOULD NOT 假定这些请求会被服务器处理。
如果服务器对 TCP 连接执行立即关闭,则存在客户端可能无法读取最后一个 HTTP 响应的重大风险。如果服务器在完全关闭的连接上从客户端接收到额外数据,例如客户端在接收服务器响应之前就发送了另一个请求,服务器的 TCP 栈将向客户端发送重置(reset)包;不幸的是,重置包可能在客户端的未确认输入缓冲被读取并由客户端的 HTTP 解析器解析之前擦除这些缓冲。
为避免 TCP 重置问题,服务器通常分阶段关闭连接。首先,服务器通过仅关闭读/写连接的写入端来执行半关闭。然后服务器继续从连接中读取,直到收到客户端的相应关闭,或直到服务器合理确定其 TCP 栈已收到客户端对包含服务器最后响应的数据包的确认。最后,服务器完全关闭连接。
尚不清楚重置问题是否仅限于 TCP,或是否也可能出现在其它传输连接协议中。
注意客户端对连接执行半关闭并不界定一个请求消息,也不意味着客户端不再关心响应。通常,不能依赖传输信号来表示边界情况,因为 HTTP/1.1 与传输无关。
9.7. TLS 连接发起
概念上,HTTP/TLS 只是将 HTTP 消息通过经 TLS 保护的连接发送,详见 [TLS13]。
HTTP 客户端同时充当 TLS 客户端。它在适当端口向服务器发起连接并发送 TLS ClientHello 来开始 TLS 握手。当 TLS 握手完成后,客户端可以发起第一个 HTTP 请求。所有 HTTP 数据 MUST 作为 TLS 的“application data”发送,但在其他方面与普通连接相同(包括可能作为持久连接重用)。
9.8. TLS 连接关闭
TLS 在(非错误的)连接关闭之前使用关闭告警的交换来提供安全的连接关闭;参见 Section 6.1 of [TLS13]。当接收到有效的关闭告警时,实现可以确认在该连接上不会再收到进一步的数据。
当实现知道它已发送或接收到所有关心的消息数据时,通常通过检测 HTTP 消息边界,它可能生成一个“incomplete close”,即发送关闭告警然后在未等待接收对端相应关闭告警的情况下关闭连接。
不完整关闭不会影响已接收数据的安全性,但它可能表明后续数据可能已被截断。由于 TLS 并不直接感知 HTTP 消息分帧,因此需要检查 HTTP 数据本身以确定消息是否完整。不完整消息的处理在 第 8 节 中定义。
在遇到不完整关闭时,客户端 SHOULD 将其认为已完成的所有请求限定为它已收到以下任一内容的请求:
- 已按 Content-Length 首部字段指定的长度接收到的数据,或
- 终止分块时的零长度分块(当使用 chunked 传输编码时)。
既无分块传输编码也无 Content-Length 的响应仅在收到有效关闭告警时才被视为完整。将不完整消息视为完整可能使实现暴露于攻击风险。
检测到不完整关闭的客户端 SHOULD 优雅地恢复。
客户端 MUST 在关闭连接之前发送关闭告警。不再期望接收任何数据的客户端 MAY 选择不等待服务器的关闭告警并直接关闭连接,从而在服务器端生成不完整关闭。
服务器 SHOULD 准备好接收来自客户端的不完整关闭,因为客户端通常能定位服务器数据的结束。
服务器 MUST 在关闭连接之前尝试与客户端发起关闭告警的交换。服务器 MAY 在发送关闭告警后关闭连接,从而在客户端产生不完整关闭。
10. 将消息作为数据封装
10.1. 媒体类型 message/http
"message/http" 媒体类型可用于封装单个 HTTP 请求或响应消息,前提是它遵守所有 "message" 类型在行长度和编码方面的 MIME 限制。由于行长度限制,"message/http" 中的字段值允许使用行折叠(obs-fold),如 第 5.2 节 所述,以便将字段值跨多行传递。接收 "message/http" 数据的实体 MUST 在使用该消息时将任何过时的行折叠替换为一个或多个 SP 字符。
- 类型名:
- message
- 子类型名:
- http
- 必须参数:
- N/A
- 可选参数:
-
version, msgtype
- version:
- 被封装消息的 HTTP 版本号(例如 "1.1")。如果不存在,该版本可以从主体的第一行确定。
- msgtype:
- 消息类型——"request" 或 "response"。如果不存在,该类型可以从主体的第一行确定。
- 编码注意事项:
- 仅允许 "7bit"、"8bit" 或 "binary"
- 安全注意事项:
- 参见 第 11 节
- 互操作性注意事项:
- N/A
- 已发布规范:
- RFC 9112(参见 第 10.1 节)。
- 使用此媒体类型的应用:
- N/A
- 片段标识符注意事项:
- N/A
- 附加信息:
-
- 魔术数字:
- N/A
- 此类型的已弃用别名:
- N/A
- 文件扩展名:
- N/A
- Macintosh 文件类型代码:
- N/A
- 用于进一步信息的联系人及电子邮件地址:
- 参见作者地址章节。
- 预期用途:
- COMMON
- 使用限制:
- N/A
- 作者:
- 参见作者地址章节。
- 变更控制者:
- IESG
10.2. 媒体类型 application/http
"application/http" 媒体类型可用于封装一条或多条 HTTP 请求或响应消息的管道(但不能混合请求与响应)。
- 类型名:
- application
- 子类型名:
- http
- 必须参数:
- N/A
- 可选参数:
-
version, msgtype
- version:
- 被封装消息的 HTTP 版本号(例如 "1.1")。如果不存在,该版本可以从主体的第一行确定。
- msgtype:
- 消息类型——"request" 或 "response"。如果不存在,该类型可以从主体的第一行确定。
- 编码注意事项:
- 此类型封装的 HTTP 消息为 "binary" 格式;通过电子邮件传输时需使用适当的 Content-Transfer-Encoding。
- 安全注意事项:
- 参见 第 11 节
- 互操作性注意事项:
- N/A
- 已发布规范:
- RFC 9112(参见 第 10.2 节)。
- 使用此媒体类型的应用:
- N/A
- 片段标识符注意事项:
- N/A
- 附加信息:
-
- 此类型的已弃用别名:
- N/A
- 魔术数字:
- N/A
- 文件扩展名:
- N/A
- Macintosh 文件类型代码:
- N/A
- 用于进一步信息的联系人及电子邮件地址:
- 参见作者地址章节。
- 预期用途:
- COMMON
- 使用限制:
- N/A
- 作者:
- 参见作者地址章节。
- 变更控制者:
- IESG
11. 安全注意事项
本节旨在告知开发者、信息提供者和用户与 HTTP 消息语法和解析相关的已知安全注意事项。关于 HTTP 语义、内容和路由的安全注意事项,见 [HTTP]。
11.1. 响应分割
响应分割(又称 CRLF 注入)是一种常见手段,用于针对 Web 的各种攻击,利用了 HTTP 消息分帧的基于行的特性以及持久连接上请求与响应的有序关联 [Klein]。当请求经过共享缓存时,该技术可能尤其具有破坏性。
响应分割利用服务器(通常在应用服务器中)的一个漏洞:攻击者可以在请求的某些参数中发送编码的数据,这些数据随后被解码并回显到响应的任一响应头字段中。如果解码后的数据被精心构造成看起来像响应已结束且随后的响应已开始,则响应被分割,攻击者即可控制表面上第二个响应的内容。随后攻击者可以在同一持久连接上发出任何其他请求,并欺骗接收者(包括中间体)相信被分割的后半部分是对第二个请求的权威响应。
例如,请求目标内的某个参数可能被应用服务器读取并在重定向时重用,导致该参数在响应的 Location 头字段中被回显。如果应用对该参数进行了 URI 解码但在放入响应字段时未正确转义,攻击者就可以发送编码的 CRLF 八位元和其他内容,使应用的单个响应看起来像是两个或多个响应。
防止响应分割的常见防御措施是过滤看起来像编码的 CR 和 LF(例如 "%0D" 和 "%0A")的请求数据。然而,这假设应用服务器只执行 URI 解码,而不是更隐蔽的数据转换(如字符集转码、XML 实体转换、base64 解码、sprintf 重格式化等)。更有效的缓解措施是禁止除服务器核心协议库之外的任何组件在首部节内发送 CR 或 LF,这意味着限制头字段输出仅使用能过滤不良八位元的 API,而不允许应用服务器直接写入协议流。
11.2. 请求走私
请求走私([Linhart])是一种利用不同接收方在协议解析上差异的技术,用以在看似无害的请求中隐藏额外请求(这些请求本可能被策略阻止或禁用)。与响应分割类似,请求走私可导致对 HTTP 使用的各种攻击。
本规范在请求解析方面引入了新的要求,尤其涉及第 6.3 节 中的消息分帧,以降低请求走私的有效性。
11.3. 消息完整性
HTTP 不定义确保消息完整性的具体机制,而是依赖底层传输协议的差错检测能力以及使用长度或分块分界来检测完整性。从历史上看,缺乏单一完整性机制被认为可以接受,因为大多数 HTTP 通信属于非正式性质。然而,HTTP 作为信息访问机制的普及导致其越来越多地被用于需要验证消息完整性的环境。
"https" 方案提供的机制(例如经认证的加密)可防止消息被篡改。然而需要注意,必须防止连接关闭被用于截断消息(见 第 9.8 节)。用户代理可能拒绝接受不完整消息或对其做特别处理。例如,用于查看病历或药物相互作用信息的浏览器需要在检测到协议传输中信息不完整、过期或损坏时向用户指示。这类机制可能通过用户代理扩展或在响应中包含消息完整性元数据时选择性启用。
"http" 方案不提供保护来防止消息被意外或恶意修改。
可通过扩展协议来缓解中间体对消息进行非期望修改的风险,即使在使用 "https" 方案时也是如此。可以通过在消息中选择性添加可扩展元数据字段的消息认证码或数字签名来保证完整性。
11.4. 消息机密性
当需要消息机密性时,HTTP 依赖底层传输协议来提供。HTTP 被特别设计为与传输协议无关,以便可在多种加密连接形式上使用,选择此类传输通常由 URI 方案或用户代理配置决定。
"https" 方案可用于标识需要机密连接的资源,如 RFC9110 第 4.2.2 节 所述。
12. IANA 注意事项
下列注册的变更控制者为:"IETF (iesg@ietf.org) - Internet Engineering Task Force"。
12.1. 字段名注册
IANA 已将下列字段名称添加到 "Hypertext Transfer Protocol (HTTP) Field Name Registry"(位于 https://www.iana.org/assignments/http-fields),如 RFC9110 第 18.4 节 所述。
12.2. 媒体类型注册
IANA 已根据第 10.1 节 和第 10.2 节 的注册信息,更新了 "Media Types" 注册表(位于 https://www.iana.org/assignments/media-types),以包含 "message/http" 和 "application/http" 媒体类型的注册信息。
12.3. 传输编码注册
IANA 已根据 第 7.3 节 的注册程序,更新了 "HTTP Transfer Coding Registry"(位于 https://www.iana.org/assignments/http-parameters/),并在下表中汇总了内容编码名称。
| 名称 | 描述 | 节 |
|---|---|---|
| chunked | 以一系列分块传输 | 7.1 |
| compress | UNIX "compress" 数据格式 [Welch] | 7.2 |
| deflate | "deflate" 压缩数据(在 "zlib" 数据格式内) ([RFC1951] 在 [RFC1950] 中定义) | 7.2 |
| gzip | GZIP 文件格式 [RFC1952] | 7.2 |
| trailers | (reserved) | 12.3 |
| x-compress | 已弃用(为 compress 的别名) | 7.2 |
| x-gzip | 已弃用(为 gzip 的别名) | 7.2 |
12.4. ALPN 协议 ID 注册
IANA 已在 "TLS Application-Layer Protocol Negotiation (ALPN) Protocol IDs" 注册表(位于 https://www.iana.org/assignments/tls-extensiontype-values/)中更新了如下注册信息:
| 协议 | 标识序列 | 参考 |
|---|---|---|
| HTTP/1.1 | 0x68 0x74 0x74 0x70 0x2f 0x31 0x2e 0x31 ("http/1.1") | RFC 9112 |
13. 参考文献
13.1. 规范性参考文献
- [CACHING]
- Fielding, R., 编辑;Nottingham, M., 编辑;J. Reschke, 编辑,“HTTP Caching”,STD 98,RFC 9111,DOI 10.17487/RFC9111,2022 年 6 月。
- [HTTP]
- Fielding, R., 编辑;Nottingham, M., 编辑;J. Reschke, 编辑,“HTTP Semantics”,STD 97,RFC 9110,DOI 10.17487/RFC9110,2022 年 6 月。
- [RFC1950]
- Deutsch, P. 与 J-L. Gailly,“ZLIB Compressed Data Format Specification version 3.3”,RFC 1950,DOI 10.17487/RFC1950,1996 年 5 月。
- [RFC1951]
- Deutsch, P.,“DEFLATE Compressed Data Format Specification version 1.3”,RFC 1951,DOI 10.17487/RFC1951,1996 年 5 月。
- [RFC1952]
- Deutsch, P.,“GZIP file format specification version 4.3”,RFC 1952,DOI 10.17487/RFC1952,1996 年 5 月。
- [RFC2119]
- Bradner, S.,“Key words for use in RFCs to Indicate Requirement Levels”,BCP 14,RFC 2119,DOI 10.17487/RFC2119,1997 年 3 月。
- [RFC5234]
- Crocker, D., 编辑;P. Overell,“Augmented BNF for Syntax Specifications: ABNF”,STD 68,RFC 5234,DOI 10.17487/RFC5234,2008 年 1 月。
- [RFC7405]
- Kyzivat, P.,“Case-Sensitive String Support in ABNF”,RFC 7405,DOI 10.17487/RFC7405,2014 年 12 月。
- [RFC8174]
- Leiba, B.,“Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”,BCP 14,RFC 8174,DOI 10.17487/RFC8174,2017 年 5 月。
- [TLS13]
- Rescorla, E.,“The Transport Layer Security (TLS) Protocol Version 1.3”,RFC 8446,DOI 10.17487/RFC8446,2018 年 8 月。
- [URI]
- Berners-Lee, T., Fielding, R., 与 L. Masinter,“Uniform Resource Identifier (URI): Generic Syntax”,STD 66,RFC 3986,DOI 10.17487/RFC3986,2005 年 1 月。
- [USASCII]
- American National Standards Institute,“Coded Character Set -- 7-bit American Standard Code for Information Interchange”,ANSI X3.4,1986 年。
- [Welch]
- Welch, T.,“A Technique for High-Performance Data Compression”,IEEE Computer 17(6),DOI 10.1109/MC.1984.1659158,1984 年 6 月。
13.2. 参考性参考文献
- [HTTP/1.0]
- Berners-Lee, T., Fielding, R., 与 H. Frystyk,“Hypertext Transfer Protocol -- HTTP/1.0”,RFC 1945,DOI 10.17487/RFC1945,1996 年 5 月。
- [Klein]
- Klein, A.,“Divide and Conquer - HTTP Response Splitting, Web Cache Poisoning Attacks, and Related Topics”,2004 年 3 月。
- [Linhart]
- Linhart, C., Klein, A., Heled, R., 与 S. Orrin,“HTTP Request Smuggling”,2005 年 6 月。
- [RFC2045]
- Freed, N. 与 N. Borenstein,“Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies”,RFC 2045,DOI 10.17487/RFC2045,1996 年 11 月。
- [RFC2046]
- Freed, N. 与 N. Borenstein,“Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types”,RFC 2046,DOI 10.17487/RFC2046,1996 年 11 月。
- [RFC2049]
- Freed, N. 与 N. Borenstein,“Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples”,RFC 2049,DOI 10.17487/RFC2049,1996 年 11 月。
- [RFC2068]
- Fielding, R., Gettys, J., Mogul, J., Frystyk, H., 与 T. Berners-Lee,“Hypertext Transfer Protocol -- HTTP/1.1”,RFC 2068,DOI 10.17487/RFC2068,1997 年 1 月。
- [RFC2557]
- Palme, J., Hopmann, A., 与 N. Shelness,“MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)”,RFC 2557,DOI 10.17487/RFC2557,1999 年 3 月。
- [RFC5322]
- Resnick, P., 编辑,“Internet Message Format”,RFC 5322,DOI 10.17487/RFC5322,2008 年 10 月。
- [RFC7230]
- Fielding, R., 编辑;J. Reschke, 编辑,“Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing”,RFC 7230,DOI 10.17487/RFC7230,2014 年 6 月。
- [RFC8126]
- Cotton, M., Leiba, B., 与 T. Narten,“Guidelines for Writing an IANA Considerations Section in RFCs”,BCP 26,RFC 8126,DOI 10.17487/RFC8126,2017 年 6 月。
附录 A. 汇总的 ABNF
BWS = <BWS, see [HTTP], Section 5.6.3> HTTP-message = start-line CRLF *( field-line CRLF ) CRLF [ message-body ] HTTP-name = %x48.54.54.50 ; HTTP HTTP-version = HTTP-name "/" DIGIT "." DIGIT OWS = <OWS, see [HTTP], Section 5.6.3> RWS = <RWS, see [HTTP], Section 5.6.3> Transfer-Encoding = [ transfer-coding *( OWS "," OWS transfer-coding ) ] absolute-URI = <absolute-URI, see [URI], Section 4.3> absolute-form = absolute-URI absolute-path = <absolute-path, see [HTTP], Section 4.1> asterisk-form = "*" authority = <authority, see [URI], Section 3.2> authority-form = uri-host ":" port chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF chunk-data = 1*OCTET chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token / quoted-string chunk-size = 1*HEXDIG chunked-body = *chunk last-chunk trailer-section CRLF field-line = field-name ":" OWS field-value OWS field-name = <field-name, see [HTTP], Section 5.1> field-value = <field-value, see [HTTP], Section 5.5> last-chunk = 1*"0" [ chunk-ext ] CRLF message-body = *OCTET method = token obs-fold = OWS CRLF RWS obs-text = <obs-text, see [HTTP], Section 5.6.4> origin-form = absolute-path [ "?" query ] port = <port, see [URI], Section 3.2.3> query = <query, see [URI], Section 3.4> quoted-string = <quoted-string, see [HTTP], Section 5.6.4> reason-phrase = 1*( HTAB / SP / VCHAR / obs-text ) request-line = method SP request-target SP HTTP-version request-target = origin-form / absolute-form / authority-form / asterisk-form start-line = request-line / status-line status-code = 3DIGIT status-line = HTTP-version SP status-code SP [ reason-phrase ] token = <token, see [HTTP], Section 5.6.2> trailer-section = *( field-line CRLF ) transfer-coding = <transfer-coding, see [HTTP], Section 10.1.4> uri-host = <host, see [URI], Section 3.2.2>
附录 B. HTTP 与 MIME 的差异
HTTP/1.1 使用了许多为 Internet Message Format [RFC5322] 和多用途互联网邮件扩展(MIME) [RFC2045] 定义的构造来允许以多种表示形式传输消息主体并使用可扩展字段。但其中一些构造已被重新解释以更好地满足交互式通信的需求,导致 MIME 构造在 HTTP 中的使用方式出现差异。这些差异是经过慎重选择以优化在二进制连接上的性能、允许更灵活地使用新媒体类型、简化日期比较并兼容常见实现。
本附录描述了 HTTP 与 MIME 在具体方面的差异。代理和网关在与严格 MIME 环境互通时需要注意这些差异并在必要时提供相应的转换。
B.1. MIME-Version
HTTP 并非严格遵循 MIME 协议。然而,消息可以包含单个 MIME-Version 首部字段以指示用于构造该消息的 MIME 协议版本。使用 MIME-Version 首部字段表示该消息完全符合 MIME 协议(如 [RFC2045] 所定义)。在将 HTTP 消息导出到严格的 MIME 环境时,发送方有责任在可能的情况下确保完全符合。
B.2. 转换到规范形式
MIME 要求在传输之前将 Internet 邮件的实体部分转换为规范形式,如 RFC2049 第 4 节 所述,并且类型为 "text" 的内容必须将行分隔表示为 CRLF,禁止在行分隔序列之外使用裸 CR 或裸 LF(见 [RFC2046])。相比之下,HTTP 并不关心内容中是否使用 CRLF、裸 CR 或裸 LF 来表示行分隔。
从 HTTP 到严格 MIME 环境的代理或网关应将文本媒体类型内的所有行分隔转换为 RFC 2049 要求的 CRLF 规范形式。但需注意,这可能因存在 Content-Encoding 而变得复杂,且 HTTP 允许使用某些字符集,这些字符集中并不使用八位元 13 和 10 来表示 CR 与 LF。
若原始内容已带有任何加密校验和,则转换会破坏这些校验和,除非原始内容已处于规范形式。因此,建议对使用此类校验和的 HTTP 内容采用规范形式。
B.3. 日期格式转换
HTTP/1.1 使用受限的日期格式集(参见 RFC9110 第 5.6.7 节)以简化日期比较。来自其它协议的代理和网关应确保消息中的任何 Date 首部字段符合 HTTP/1.1 的格式之一,并在必要时重写该日期。
B.4. 内容编码的转换
MIME 并不包含与 HTTP 的 Content-Encoding 首部字段等价的概念。由于该字段作为媒体类型的修饰器,HTTP 到 MIME 的代理和网关应当要么更改 Content-Type 首部的值,要么在转发消息之前对表示进行解码。(一些用于 Internet 邮件的试验性 Content-Type 用法通过参数 ";conversions=<content-coding>" 提供了类似功能,但该参数并非 MIME 标准的一部分。)
B.5. Content-Transfer-Encoding 的转换
HTTP 不使用 MIME 的 Content-Transfer-Encoding 字段。从 MIME 合规协议到 HTTP 的代理和网关需要在将响应消息传递给 HTTP 客户端之前移除任何 Content-Transfer-Encoding。
从 HTTP 到 MIME 合规协议的代理和网关负责确保消息以适当的格式和编码进行转换,以便在目标协议上安全传输,“安全传输”由所使用协议的限制定义。若进行适当转换并使用合适的 Content-Transfer-Encoding 能提高在目标协议上安全传输的可能性,则代理或网关应进行该转换并标注相应的 Content-Transfer-Encoding。
B.6. MHTML 与行长限制
与 MHTML [RFC2557] 共用代码的 HTTP 实现需要注意 MIME 的行长限制。由于 HTTP 本身没有此限制,因此 HTTP 不会折叠长行。通过 HTTP 传输的 MHTML 消息应遵循 MHTML 的所有约定,包括行长限制与折叠、规范化等,因为 HTTP 在不修改消息主体的情况下传输内容,且(除 "multipart/byteranges" 类型外)不会解释其中可能包含的内容或 MIME 首部行。
附录 C. 与以前 RFC 的差异
C.1. 来自 HTTP/0.9 的变化
由于 HTTP/0.9 不支持请求中的首部字段,因此它无法支持基于名称的虚拟主机(通过检查 Host 首部字段来选择资源)。实现基于名称的虚拟主机的服务器应禁用对 HTTP/0.9 的支持。大多数看起来像 HTTP/0.9 的请求实际上是因客户端未正确编码 request-target 而构造不良的 HTTP/1.x 请求。
C.2. 来自 HTTP/1.0 的变化
C.2.1. 多宿主网站服务器
客户端和服务器需支持 Host 首部字段(见 RFC9110 第 7.2 节),当 HTTP/1.1 请求缺少该首部字段时报告错误,并接受绝对 URI(见第 3.2 节)——这些是 HTTP/1.1 定义的最重要变更之一。
较早的 HTTP/1.0 客户端假定 IP 地址与服务器是一一对应的关系;当时没有通过其他机制来区分请求所针对的服务器,除非检查请求所定向的 IP 地址。Host 首部字段是在开发 HTTP/1.1 时引入的,尽管它很快被大多数 HTTP/1.0 浏览器实现,但为确保全面采用,HTTP/1.1 对所有请求施加了额外要求。截至撰写时,大多数基于 HTTP 的服务都依赖 Host 首部字段来定位请求目标。
C.2.2. Keep-Alive 连接
在 HTTP/1.0 中,每个连接由客户端在请求之前建立,由服务器在发送响应后关闭。然而,一些实现实现了在 RFC2068 第 19.7.1 节 中描述的显式协商的持久连接("Keep-Alive")。
一些客户端与服务器可能希望兼容这些早期的持久连接方法,通过在请求中显式协商 "Connection: keep-alive" 头字段来实现。然而,一些实验性的 HTTP/1.0 持久连接实现有缺陷;例如,如果某个 HTTP/1.0 代理不理解 Connection,它会将该头字段错误地转发到下一个入站服务器,从而导致连接挂起。
曾尝试引入专门针对代理的 Proxy-Connection 首部字段来解决该问题。但实际上这也不可行,因为代理通常部署为多层,导致前述相同问题再次出现。
因此,建议客户端不要在任何请求中发送 Proxy-Connection 首部字段。
客户端在考虑在请求中使用 "Connection: keep-alive" 时也应谨慎;虽然它们可以与 HTTP/1.0 服务器启用持久连接,但使用该机制的客户端需要监控连接以检测“挂起”请求(这表明客户端应停止发送该首部字段),且在使用代理时不应使用该机制。
C.2.3. 引入 Transfer-Encoding
HTTP/1.1 引入了 Transfer-Encoding 首部字段(见第 6.1 节)。在将消息通过 MIME 合规协议转发之前,必须先对传输编码进行解码。
C.3. 来自 RFC 7230 的变更
介绍 HTTP 设计目标、历史、架构、一致性准则、协议版本控制、URI、消息路由和首部字段的大部分章节已移至 [HTTP]。本文档现仅保留与 HTTP/1.1 消息语法和连接管理相关的要求。
禁止在内容之外使用裸 CR。(见 第 2.2 节)
authority-form 的 ABNF 定义已从 URI 的更通用的 authority 组件(其端口可选)更改为 CONNECT 所要求的特定 host:port 格式。(见第 3.2.3 节)
接收方在处理不明确的消息分帧时必须避免走私/分割攻击。(见 第 6.1 节)
在分块扩展的 ABNF 中,围绕 ";" 和 "=" 的(不良)空白已被重新引入。空白在 RFC7230 中被移除,但该更改被发现会破坏现有实现。(见 第 7.1.1 节)
致谢
参见 RFC9110 的“致谢”附录,该附录同样适用于本文档。
索引
- A
- C
- D
- deflate(传输编码) 7.2
- F
- G
- 语法 (Grammar)
- absolute-form 3.2, 3.2.2
- ALPHA 1.2
- asterisk-form 3.2, 3.2.4
- authority-form 3.2, 3.2.3
- chunk 7.1
- chunk-data 7.1
- chunk-ext 7.1, 7.1.1
- chunk-ext-name 7.1.1
- chunk-ext-val 7.1.1
- chunk-size 7.1
- chunked-body 7.1
- CR 1.2
- CRLF 1.2
- CTL 1.2
- DIGIT 1.2
- DQUOTE 1.2
- field-line 5, 7.1.2
- field-name 5
- field-value 5
- HEXDIG 1.2
- HTAB 1.2
- HTTP-message 2.1
- HTTP-name 2.3
- HTTP-version 2.3
- last-chunk 7.1
- LF 1.2
- message-body 6
- method 3.1
- obs-fold 5.2
- OCTET 1.2
- origin-form 3.2, 3.2.1
- reason-phrase 4
- request-line 3
- request-target 3.2
- SP 1.2
- start-line 2.1
- status-code 4
- status-line 4
- trailer-section 7.1, 7.1.2
- Transfer-Encoding 6.1
- VCHAR 1.2
- gzip(传输编码) 7.2
- 语法 (Grammar)
- H
- 首部字段(Header Fields)
- header line(首部行) 2.1
- header section(首部节) 2.1
- headers(首部) 2.1
- HTTP 1, 1, 1.1, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 1.2, 2, 2.3, 3, 3, 3.1, 3.2, 3.2, 3.2.1, 3.2.2, 3.2.3,
3.2.4, 3.3, 3.3, 4, 5, 6, 6, 6.1, 6.1, 6.1, 6.1, 6.2, 6.2, 6.3, 7, 7.1.2, 7.2, 7.2, 7.2, 7.3, 7.3, 7.4, 7.4, 7.4, 7.4, 9, 9, 9.2, 9.3, 9.3.1, 9.3.2, 9.3.2,
9.6, 11, 11.4, 12.1, 12.3, 13.1, A, A, A, A, A, A, A, A, A, A, A, B.3, B.6, C.2.1, C.3, "Acknowledgements"
- Section 4.1 A
- Section 5.1 A
- Section 5.5 A
- Section 5.6.2 A
- Section 5.6.3 A, A, A
- Section 5.6.4 A, A
- Section 10.1.4 A
- Section 2 1.1
- Section 2.3 3
- Section 2.5 2.3
- Section 3 2
- Section 4.1 1.2
- Section 4.2 3.2
- Section 4.2.1 9
- Section 4.2.2 11.4
- Section 5.1 1.2
- Section 5.5 1.2, 5
- Section 5.6.1 1.2, 6.3, A
- Section 5.6.2 1.2
- Section 5.6.3 1.2, 1.2, 1.2
- Section 5.6.4 1.2, 1.2
- Section 5.6.7 B.3
- Section 6.4 6
- Section 6.4.1 6
- Section 6.5 7.1.2, 7.4
- Section 7.1 3.3
- Section 7.2 3.2, 3.2.1, C.2.1
- Section 7.3 9
- Section 7.4 3.3
- Section 7.6 3.2.2
- Section 7.6.1 7.4, 9.3, 9.6
- Section 8.4.1 6.1, 7.3
- Section 8.4.1.1 7.2
- Section 8.4.1.2 7.2
- Section 8.4.1.3 7.2
- Section 8.6 6.2, 6.2
- Section 9 3.1
- Section 9.2.1 9.3.2
- Section 9.2.2 9.3.1, 9.3.2
- Section 9.3.6 3.2.3, 6.1
- Section 9.3.7 3.2.4
- Section 10.1.4 1.2, 6.1, 7, 7.3, 7.4, 12.3
- Section 12.4.2 7.4
- Section 14.6 B.6
- Section 15 4
- Section 15.2 9.2
- Section 15.4.5 6.1
- Section 15.5.15 3
- Section 18.4 12.1
- Acknowledgements "Acknowledgements"
- HTTP/1.0 2.3, 13.2
- K
- L
- M
- O
- origin-form(request-target 的形式) 3.2.1
- R
- request-target 3.2
- RFC1950 12.3, 13.1
- RFC1951 12.3, 13.1
- RFC1952 12.3, 13.1
- RFC2045 2.1, 6.1, 13.2, B, B.1
- Section 6 6.1
- RFC2046 13.2, B.2
- RFC2049 13.2, B.2
- Section 4 B.2
- RFC2068 13.2, C.2.2
- Section 19.7.1 C.2.2
- RFC2119 1.1, 13.1
- RFC2557 13.2, B.6
- RFC5234 1.2, 1.2, 13.1
- Appendix B.1 1.2
- RFC5322 2.1, 13.2, B
- RFC7230 1, 1, 13.2, C.3
- RFC7405 1.2, 13.1
- RFC8126 7.3, 13.2
- Section 4.8 7.3
- RFC8174 1.1, 13.1
- T
- U
- W
- X