跳到主要内容

附录 A. HTTP 版本历史

HTTP 自 1990 年起就在使用. 其第一个版本后来被称为 HTTP/0.9, 是一个用于在 Internet 上传输超文本数据的简单协议, 只使用单个请求方法 (GET), 并且没有元数据. 由 [RFC1945] 定义的 HTTP/1.0 增加了一系列请求方法和类 MIME 的消息传递, 允许传输元数据, 并可在请求/响应语义上附加修饰. 然而, HTTP/1.0 没有充分考虑层级代理、缓存、持久连接需求以及基于名称的虚拟主机所带来的影响. 自称为 "HTTP/1.0" 的实现不完整的应用大量涌现, 这进一步使得必须变更协议版本, 以便两个通信应用能够判断彼此的真实能力.

HTTP/1.1 通过包含更严格的要求来实现可靠实现, 从而保持与 HTTP/1.0 兼容; 它只增加那些要么可以被 HTTP/1.0 接收方安全忽略, 要么只在与声明遵从 HTTP/1.1 的一方通信时才发送的特性.

HTTP/1.1 的设计使得支持以前的版本很容易. 通用 HTTP/1.1 服务器应当能够理解 HTTP/1.0 格式的任何合法请求, 并以一条只使用 HTTP/1.0 客户端所能理解 (或能安全忽略) 的特性的 HTTP/1.1 消息作出适当响应. 同样, 可以预期 HTTP/1.1 客户端能够理解任何合法的 HTTP/1.0 响应.

由于 HTTP/0.9 不支持请求中的头部字段, 它没有任何机制来支持基于名称的虚拟主机 (即通过检查 Host 头部字段来选择资源). 任何实现基于名称的虚拟主机的服务器都应当禁用对 HTTP/0.9 的支持. 大多数看起来像 HTTP/0.9 的请求, 实际上都是客户端未能正确编码请求目标而造成的、构造拙劣的 HTTP/1.x 请求.

A.1. 与 HTTP/1.0 的变化​

本节概述 HTTP/1.0 与 HTTP/1.1 两个版本之间的主要差异.

A.1.1. 多宿主 Web 服务器​

要求客户端和服务器支持 Host 头部字段 (第 5.4 节)、在 HTTP/1.1 请求缺少该字段时报错, 以及接受绝对 URI (第 5.3 节), 这些是 HTTP/1.1 所定义的最重要变更之一.

较早的 HTTP/1.0 客户端假定 IP 地址与服务器是一对一的关系; 除了请求所指向的 IP 地址之外, 当时没有其他既定机制来区分请求所意图的服务器. Host 头部字段是在 HTTP/1.1 的开发过程中引入的; 尽管大多数 HTTP/1.0 浏览器很快就实现了它, 但为了保证被完全采用, 所有 HTTP/1.1 请求都被施加了额外要求. 在撰写本文时, 大多数基于 HTTP 的服务都依赖 Host 头部字段来定位请求.

A.1.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 服务器建立持久连接, 但使用它的客户端将需要监视连接是否出现 "挂起" 的请求 (这表明客户端应当停止发送该头部字段), 而且在使用代理时, 客户端根本不应使用该机制.

A.1.3. 引入 Transfer-Encoding​

HTTP/1.1 引入了 Transfer-Encoding 头部字段 (第 3.3.1 节). 在通过符合 MIME 的协议转发 HTTP 消息之前, 传输编码需要被解码.

A.2. 与 RFC 2616 的变化​

HTTP 的错误处理方式已得到说明. (第 2.5 节)

HTTP-version 的 ABNF 产生式已明确为区分大小写. 此外, 版本号被限制为单个数字, 原因在于已知有些实现无法正确处理多位数版本号. (第 2.6 节)

由于与在网络上传输相关的安全问题, 现在不再允许在 HTTP 和 HTTPS URI 中使用 userinfo (即用户名和口令). (第 2.7.1 节)

HTTPS URI 方案现在由本规范定义; 此前它定义在 [RFC2818] 第 2.4 节中. 此外, 它蕴含端到端的安全性. (第 2.7.2 节)

HTTP 消息可以 (并且经常) 被实现缓冲; 尽管有时它可以作为流使用, 但 HTTP 从根本上是一种面向消息的协议. 为提升互操作性, 已对各种协议元素的最小支持大小给出建议. (第 3 节)

现在要求拒绝字段名周围无效的空白, 因为接受它代表一种安全漏洞. 定义头部字段的 ABNF 产生式现在只列出字段值. (第 3.2 节)

关于某些文法产生式之间隐含线性空白的规则已被移除; 现在只有在 ABNF 中明确指定的地方才允许出现空白. (第 3.2.3 节)

跨多行的头部字段 ("行折叠") 已被弃用. (第 3.2.4 节)

comment 和 quoted-string 文本中不再允许 NUL 八位组, 其中反斜杠转义的处置方式也已明确. quoted-pair 规则不再允许对 HTAB 之外的控制字符进行转义. 头部字段和原因短语中的非 US-ASCII 内容已被废弃并变为不透明 (TEXT 规则已被移除). (第 3.2.6 节)

现在要求接收方把伪造的 Content-Length 头部字段当作错误处理. (第 3.3.2 节)

确定消息主体长度的算法已被明确, 以指出所有影响它的特殊情况 (例如由方法或状态码驱动的), 并指出新的协议元素不能定义这类特殊情况. CONNECT 是确定消息主体长度时新增的一种特殊情况. "multipart/byteranges" 不再是确定消息主体长度的一种方式. (第 3.3.3 节)

"identity" 传输编码 token 已被移除. (第 3.3 和 4 节)

块长度不包含块头部和尾部中八位字节的计数. 块扩展中的行折叠已被禁止. (第 4.1 节)

"deflate" 内容编码的含义已得到明确. (第 4.2.2 节)

请求目标改用 RFC 3986 的 segment 加 query 分量来定义, 而不再使用 RFC 1808 的 abs_path. 请求目标的 asterisk-form 只允许与 OPTIONS 方法一起使用. (第 5.3 节)

引入了 "有效请求 URI" (Effective Request URI) 这一术语. (第 5.5 节)

网关不再需要生成 Via 头部字段. (第 5.7.1 节)

何时必须发送 "close" 连接选项已得到明确. 此外, "逐跳" (hop-by-hop) 头部字段必须出现在 Connection 头部字段中; 不能仅因为本规范把它们定义为逐跳就免除此要求. (第 6.1 节)

每台服务器两个连接的限制已被移除. 不再要求必须重试幂等的一批请求. 关于 "在服务器过早关闭连接时某些情况下必须重试请求" 的要求已被移除. 此外, 关于 "何时允许服务器过早关闭连接" 的一些多余要求也已被移除. (第 6.3 节)

Upgrade 头部字段的语义现在也在 101 之外的响应中定义 (这一点取自 [RFC2817]). 此外, 字段值中的顺序现在是有意义的. (第 6.7 节)

列表产生式中的空列表元素 (例如包含 ", ," 的列表头部字段) 已被弃用. (第 7 节)

传输编码的登记现在需要 IETF Review (第 8.4 节)

本规范现在定义 Upgrade Token 注册表, 它此前定义在 [RFC2817] 第 7.2 节中. (第 8.6 节)

对支持 HTTP/0.9 请求的期望已被移除. (附录 A)

指出了请求中 Keep-Alive 和 Proxy-Connection 头部字段的问题, 并且完全不鼓励使用后者. (附录 A.1.2)