互联网工程任务组 (IETF) R. Fielding, 编辑
征求意见稿: 9110 Adobe
废止: 2818, 7230, 7231, 7232, 7233, 7235, 7538, 7615, 7694 M. Nottingham, 编辑
STD: 97 Fastly
更新: 3864 J. Reschke, 编辑
类别: 标准轨道 greenbytes
ISSN: 2070-1721 2022年6月

HTTP 语义


摘要

超文本传输协议 (HTTP) 是一种无状态的应用层协议,用于 分布式、协作式超文本信息系统。本文档描述 HTTP 的总体架构,确立通用术语,并定义相关方面,所涉及的 协议内容为所有版本所共有。此定义涵盖核心协议元素、 可扩展性机制,以及 "http" 和 "https" 统一资源标识符 (URI) 方案。

本文档更新 RFC 3864,并废止 RFC 2818、7231、7232、7233、7235、7538、7615、 7694,以及 7230 的部分内容。

本备忘录的状态

这是一份互联网标准轨道文档。

本文档是互联网工程任务组 (IETF) 的成果。它代表 IETF 社区的共识。它已接受公开审查,并已获准 发布,批准机构为互联网工程指导组 (IESG)。更多信息涉及 互联网标准,可参见 RFC 7841 第 2 节。

有关本文档当前状态、任何勘误以及如何提供 针对本文档的反馈的信息,可从以下地址获取 https://www.rfc-editor.org/info/rfc9110。

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. 介绍

1.1. 目的

超文本传输协议 (HTTP) 是一个无状态的应用层 请求/响应协议族,它们共享通用接口、可扩展语义以及 自描述消息,从而实现与基于网络的超文本 信息系统的灵活交互。

HTTP 通过向客户端提供一个与所提供资源类型无关的统一接口, 隐藏服务实现方式的细节。同样,服务器也 无需了解每个客户端的用途:可以单独考虑请求, 而不是将其与特定类型的客户端或预先确定的 应用步骤序列相关联。这使得通用实现能够有效地用于 许多不同的上下文中,降低交互复杂性,并实现随时间 独立演进。

HTTP 还被设计为用作中介协议,其中代理和网关 可以将非 HTTP 信息系统转换为更通用的接口。

这种灵活性的一个结果是,不能根据接口背后 发生的事情来定义协议。相反,我们只能定义 通信的语法、所接收通信的意图以及 接收方的预期行为。如果单独考虑通信,那么成功的操作 应当反映在服务器所提供的可观察接口的相应变化中 。但是,由于多个客户端可能并行操作,并且可能 目标相互冲突,因此我们不能要求这种变化在单个 响应的范围之外可观察到。

1.2. 历史与演进

自 1990 年推出以来,HTTP 一直是万维网的主要信息传输协议 。它最初是一种用于低延迟请求的简单机制,只有一种 方法 (GET),用于请求传输由给定路径名标识的假定超文本文档 。随着 Web 的发展,HTTP 得到扩展,将请求和响应封装 在消息中,使用类似 MIME 的媒体类型传输任意数据格式,并通过 中间方路由请求。这些协议最终被定义为 HTTP/0.9 和 HTTP/1.0(参见 [HTTP/1.0])。

HTTP/1.1 旨在改进协议特性,同时保持与 现有基于文本的消息传递语法的兼容性,提高其在整个 Internet 上的互操作性、 可扩展性和健壮性。其中包括针对固定和动态(分块)内容的 基于长度的数据分隔符、一套一致的内容协商框架、 用于条件请求的不透明验证器、用于提高缓存一致性的缓存控制、 用于部分更新的范围请求以及默认的持久 连接。HTTP/1.1 于 1995 年推出,并于 1997 年在标准轨道上发布 [RFC2068],于 1999 年修订 [RFC2616],并 于 2014 年再次修订([RFC7230] 至 [RFC7235])。

HTTP/2([HTTP/2]) 在现有 TLS 和 TCP 协议之上引入了多路复用会话层,用于 通过高效的字段压缩和服务器推送交换并发 HTTP 消息。 HTTP/3([HTTP/3]) 通过使用 QUIC 作为基于 UDP 的安全 多路复用传输而不是 TCP,为并发消息提供了更大的独立性。

HTTP 的三个主要版本都依赖本文定义的语义。它们 并未彼此废弃,因为每个版本都有特定的优点和局限性, 具体取决于使用上下文。实现应当选择最 适合其特定上下文的传输和消息传递语法。

本次 HTTP 修订将语义(本文)和缓存的定义 ([CACHING])与当前 HTTP/1.1 消息传递 语法([HTTP/1.1])分离,以允许每个主要协议版本 在引用相同核心语义的同时独立演进。

1.3. 核心 语义

HTTP 提供了一个用于与资源(第 3.1 节)交互的统一接口——无论其类型、性质或 实现如何——通过发送操作或传输表示(第 3.2 节)的消息来实现。

每条消息要么是请求,要么是响应。客户端构造用于 传达其意图的请求消息,并将这些消息路由到已标识的源服务器。 服务器监听请求,解析收到的每条消息,根据已标识的 目标资源解释消息语义,并以一个或多个 响应消息响应该请求。客户端检查收到的响应,以查看其 意图是否得到执行,并根据状态码和 收到的内容确定下一步操作。

HTTP 语义包括每种请求方法(第 9 节)所定义的意图、可能在 请求头字段中描述的对这些语义的扩展、描述响应的状态码(第 15 节)以及其他可能 在响应字段中给出的控制数据和资源元数据。

语义还包括描述 接收方应当如何解释内容的表示元数据、可能影响 内容选择的请求头字段,以及统称为 内容协商(第 12 节)的各种选择算法。

1.4. 由本文废弃的 规范

表 1
标题 参考文献 参见
基于 TLS 的 HTTP [RFC2818] B.1
HTTP/1.1 消息语法和路由 [*] [RFC7230] B.2
HTTP/1.1 语义和内容 [RFC7231] B.3
HTTP/1.1 条件请求 [RFC7232] B.4
HTTP/1.1 范围请求 [RFC7233] B.5
HTTP/1.1 身份验证 [RFC7235] B.6
HTTP 状态码 308(永久重定向) [RFC7538] B.7
HTTP Authentication-Info 和 Proxy-Authentication-Info 响应头字段 [RFC7615] B.8
HTTP 客户端发起的 Content-Encoding [RFC7694] B.9

[*] 本文仅废弃 RFC 7230 中独立于 HTTP/1.1 消息传递语法和 连接管理的部分;RFC 7230 的其余部分由“HTTP/1.1”[HTTP/1.1] 废弃。

2. 一致性

2.1. 语法 表示法

本规范使用 [RFC5234] 中的扩充巴科斯-瑙尔范式 (ABNF) 表示法, 并使用 [RFC7405] 中定义的字符串区分大小写表示法进行了扩展。

它还使用 第 5.6.1 节中定义的列表扩展,该扩展允许使用“#”运算符紧凑地 定义逗号分隔的列表(类似于“*” 运算符表示重复的方式)。附录 A 展示了将所有列表 运算符扩展为标准 ABNF 表示法后的汇总语法。

按照约定,以“obs-”为前缀的 ABNF 规则名称表示因 历史原因而出现的废弃语法规则。

以下核心规则通过引用纳入,如 附录 B.1 中 [RFC5234] 所定义: ALPHA(字母)、CR(回车)、CRLF(CR LF)、CTL(控制字符)、DIGIT(十进制 0-9)、DQUOTE(双引号)、HEXDIG(十六进制 0-9/A-F/a-f)、HTAB(水平制表符)、LF (换行)、OCTET(任意 8 位数据序列)、SP(空格)和 VCHAR(任意可见的 US-ASCII 字符)。

第 5.6 节定义了一些用于字段值的通用语法组件。

本规范使用术语“字符”、“字符编码方案”、“字符集” 和“协议元素”,其定义见 [RFC6365]。

2.2. 要求表示法

本文中的关键词“必须”、“不得”、“要求”、“应当”、“不得”、“应该”、“不应该”、“推荐”、“不推荐”、“可以”和“可选”应按照 BCP 14 [RFC2119] [RFC8174] 中所述进行解释,但仅当它们像此处所示全部以大写形式出现时如此。

本规范根据参与者在 HTTP 通信中的角色来确定一致性标准。因此,要求适用于发送方、接收方、客户端、 服务器、用户代理、中间方、源服务器、代理、网关或缓存, 具体取决于该要求所约束的行为。当要求适用于单次通信范围之外时,还会对 实现、资源所有者以及协议元素 注册提出额外要求。

当某项要求仅适用于 创建协议元素的实现,而非将收到的元素 向下游转发的实现时,使用动词“生成”而不是“发送”。

如果一个实现符合与其在 HTTP 中所承担角色 相关的所有要求,则认为该实现是一致的。

发送方不得生成与相应 ABNF 规则所定义 语法不匹配的协议元素。在给定消息中,发送方不得生成仅允许由其他角色的参与者 生成的协议元素或语法替代形式(即发送方在该 消息中不具有的角色)。

符合 HTTP 既包括符合所使用 协议版本的特定消息传递语法,也包括符合所发送协议元素的语义。例如, 声称符合 HTTP/1.1 但无法识别 HTTP/1.1 接收方所需特性的客户端,将无法与 根据这些声明调整其响应的服务器互操作。反映用户 选择的特性(例如内容协商和用户选择的扩展)可能会影响 协议流之外的应用程序行为;发送不能准确 反映用户选择的协议元素会使用户困惑并妨碍其选择。

当实现不符合语义一致性时,该实现消息的接收方 最终会开发变通方法以相应调整其行为。如果这些变通方法仅限于有缺陷的实现, 接收方可以在保持符合 本协议的同时采用此类变通方法。例如, 服务器通常会扫描 User-Agent 字段值的部分内容,而用户代理 通常会扫描 Server 字段值,以针对已知的 缺陷或选择不当的默认值调整自身行为。

2.3. 长度要求

接收方应该以防御性方式解析收到的协议元素, 只应最低限度地预期该元素会符合其 ABNF 语法并 能够容纳在合理大小的缓冲区内。

HTTP 对许多协议元素没有规定具体的长度限制,因为 合适的长度可能因部署 上下文和实现用途而有很大差异。因此,发送方与 接收方之间的互操作性取决于对每个 协议元素的合理长度有共同预期。此外,在过去三十年的 HTTP 使用过程中, 对某些协议元素的合理长度通常如何理解已经发生变化 ,并且预计未来还会继续变化。

至少,接收方必须能够解析和处理 长度至少与其在其他消息中为 相同协议元素生成的值一样长的协议元素。例如,发布指向其自身资源的 很长 URI 引用的源服务器,需要能够解析和 处理作为目标 URI 收到的这些相同引用。

许多收到的协议元素仅解析到足以识别并 将该元素向下游转发的程度。例如,中间方可能会将收到的 字段解析为字段名称和字段值组件,但随后在不 进一步解析字段值内部内容的情况下转发该字段。

2.4. 错误处理

接收方必须按照 本规范为收到的协议元素定义的语义来解释该元素,包括对本 规范的扩展,除非接收方已经(通过经验或配置) 确定发送方错误地实现了这些语义所蕴含的内容。例如, 如果检查收到的 Accept-Encoding 头字段时 User-Agent 头字段 表明某个特定实现版本已知在收到某些 内容编码时会失败,则源服务器可以忽略该字段的内容。

除非另有说明,否则接收方可以尝试从 无效构造中恢复可用的协议元素。HTTP 不定义特定的错误 处理机制,除非这些机制会对安全产生直接影响,因为协议的不同 应用需要不同的错误处理策略。例如, Web 浏览器可能希望从 Location 头字段无法按照 ABNF 解析的响应中透明恢复,而系统控制客户端可能认为任何形式的错误 恢复都是危险的。

在底层连接失败时,某些请求可以由客户端自动重试, 如 第 9.2.2 节所述。

2.5. 协议版本

HTTP 的版本号由两个以“.”(句点或 小数点)分隔的十进制数字组成。第一个数字(主版本)表示消息传递语法,而 第二个数字(次版本)表示发送方在该主 版本中所符合(能够理解以用于未来通信)的最高次版本。

虽然 HTTP 的核心语义不会因协议版本而改变,但它们“在线路上”的 表达方式可能会改变,因此当线路格式发生不兼容的更改时, HTTP 版本号也会改变。此外,HTTP 允许通过使用 已定义的扩展点(第 16 节),在不更改版本的情况下 对协议进行增量的、向后兼容的更改。

整个协议版本表示发送方符合该版本相应规范中规定的 一组要求。例如, “HTTP/1.1”版本由本文、“HTTP 缓存”[CACHING] 和“HTTP/1.1”[HTTP/1.1] 这些规范共同定义。

当引入不兼容的消息语法时,HTTP 的主版本号会 递增。当协议发生的更改具有 增加消息语义或暗示发送方具有额外能力的 效果时,次版本号会递增。

即使发送方仅使用协议中向后兼容的子集,次版本也会公布发送方的通信能力, 从而让 接收方知道可以在响应中(由服务器)或在 未来请求中(由客户端)使用更高级的特性。

当 HTTP 的某个主版本没有定义任何次版本时,隐含次版本为“0”。 当在需要 次版本标识符的元素中引用该协议时,使用“0”。

3. 术语和 核心概念

HTTP 是为万维网 (WWW) 架构创建的,并随着时间推移不断演进,以 支持全球超文本系统的可扩展性需求。该架构的很大一部分 反映在定义 HTTP 所使用的术语中。

3.1. 资源

HTTP 请求的目标称为资源。HTTP 不限制 资源的性质;它仅定义了可用于与 资源交互的接口。大多数资源由统一资源标识符 (URI) 标识,如 第 4 节所述。

HTTP 的一个设计目标是将资源标识与请求语义分离, 这是通过将请求语义赋予请求方法(第 9 节)以及少数修改请求的头 字段来实现的。资源不能以与请求方法语义 不一致的方式处理请求。例如,尽管资源的 URI 可能暗示 不安全的语义,但客户端可以预期资源在处理使用安全方法的请求时 避免执行不安全的操作(参见 第 9.2.1 节)。

HTTP 依赖统一资源标识符 (URI) 标准 [URI] 来 指示目标资源(第 7.1 节)以及 资源之间的关系。

3.2. 表示

表示是旨在反映给定资源过去、当前 或所需状态的信息,其格式可以方便地通过 协议进行传输。表示由一组表示元数据和一条 可能无界的表示数据流(第 8 节)组成。

HTTP 通过针对资源状态的可传输表示定义通信, 而不是传输资源本身,从而允许在其统一接口背后进行“信息隐藏”。 这使得由 URI 标识的资源可以是 任何事物,包括“拉古纳海滩当前天气”之类的时间函数,同时 可以提供表示生成消息时该资源的 信息 [REST]。

统一接口类似于一扇窗口,人们只能通过向另一侧的独立参与者 传递消息,来观察某个事物并对其采取 操作。在我们的通信中,需要一种共享抽象来表示(“代替”)该事物当前或 所需的状态。当表示是超文本时, 它既可以提供资源状态的表示,也可以提供 有助于指导接收方未来交互的处理指令。

目标资源可能提供或能够 生成多个表示,每个表示都旨在反映资源的 当前状态。通常会使用基于内容协商(第 12 节)的算法,从这些 表示中选择一个最适用于给定请求的表示。这个选定的 表示提供用于评估条件 请求(第 13 节) 并构造对 GET(第 9.3.1 节)的 200 (OK)、206(部分内容)和 304(未修改)响应内容的数据和元数据。

3.3. 连接、客户端和服务器

HTTP 是一种运行在可靠的传输层或 会话层连接之上的客户端/服务器协议。

HTTP 客户端是为了发送一个或多个 HTTP 请求而与服务器建立连接的 程序。HTTP 服务器是一个 接受连接以通过发送 HTTP 响应来处理 HTTP 请求的程序。

术语客户端和服务器仅指这些程序针对 特定连接所执行的角色。同一个程序可能在某些连接上充当客户端,而在 其他连接上充当服务器。

HTTP 被定义为无状态协议,这意味着每个请求消息的语义 都可以单独理解,而且连接与其上的 消息之间的关系不会影响这些消息的解释。例如, CONNECT 请求(第 9.3.6 节)或带有 Upgrade 头字段的请求(第 7.8 节)可以在任何 时间发生,而不仅仅是在连接上的第一条消息中。许多实现依赖 HTTP 的无状态设计来重用代理连接,或者跨多个服务器动态地对请求进行 负载均衡。

因此,服务器不得假定同一连接上的两个请求 来自同一用户代理,除非该连接是安全的并且 专用于该代理。已知某些非标准 HTTP 扩展(例如 [RFC4559]) 会违反这一要求,从而导致安全和互操作性 问题。

3.4. 消息

HTTP 是一种用于通过 连接交换消息的无状态请求/响应协议。术语发送方和 接收方分别指发送或接收给定消息的任何实现。

客户端以带有 方法(第 9 节)和请求目标(第 7.1 节)的请求消息形式向服务器发送请求。 请求还可能包含用于请求修饰符、客户端信息 和表示元数据的头字段(第 6.3 节)、旨在按照方法进行处理的 内容(第 6.4 节),以及用于传达 发送内容时收集的信息的尾部字段(第 6.5 节)。

服务器通过发送一个或多个响应 消息来响应客户端的请求,每个消息都包含状态码(第 15 节)。响应还可能包含用于 服务器信息、资源元数据和表示元数据的头字段、要 根据状态码解释的内容,以及用于传达 发送内容时收集的信息的尾部字段。

3.5. 用户 代理

术语用户代理指发起 请求的各种客户端程序中的任何一种。

最熟悉的用户代理形式是通用 Web 浏览器,但这仅占 实现中的一小部分。其他常见的用户代理包括蜘蛛程序 (遍历 Web 的机器人)、命令行工具、广告牌屏幕、家用电器、 秤、灯泡、固件更新脚本、移动应用程序以及各种 形状和尺寸的通信设备。

作为用户代理并不意味着在发出请求时有人类用户直接与 软件代理交互。在许多情况下,用户代理被安装或 配置为在后台运行,并保存其结果以供稍后检查(或仅保存 其中可能有意义或存在错误的结果子集)。例如,蜘蛛程序 通常会获得一个起始 URI,并被配置为在 将 Web 作为超文本图进行爬取时遵循某些行为。

许多用户代理无法或选择不向其用户提供交互式建议, 或对安全或隐私问题提供充分警告。在本 规范要求向用户报告错误的少数情况下,这类 报告仅能在错误控制台或日志文件中观察到也是可以接受的。同样, 要求自动操作在继续之前由用户确认的要求,可以通过 预先配置选择、运行时选项或简单地避免不安全的 操作来满足;如果用户已经做出了该选择,确认并不意味着需要任何特定的用户界面或中断 正常处理。

3.6. 源服务器

术语源服务器指能够为给定目标资源生成权威 响应的程序。

最熟悉的源服务器形式是大型公共网站。然而,就像把用户 代理等同于浏览器一样,人们很容易被误导,认为所有 源服务器都相同。常见的源服务器还包括家庭自动化设备、 可配置的网络组件、办公机器、自主机器人、新闻源、 交通摄像头、实时广告选择器以及视频点播平台。

大多数 HTTP 通信由对某个 URI 所标识资源表示的检索请求 (GET) 构成。在最简单的情况下,这可以通过 用户代理 (UA) 与源 服务器 (O) 之间的单个双向连接 (===) 来完成。

         请求   >

    UA ======================================= O

                                <   响应

3.7. 中间方

HTTP 允许使用中间方通过一系列 连接来满足请求。HTTP 中间方有三种常见形式:代理、 网关和隧道。在某些情况下,单个中间方可能充当源服务器、 代理、网关或隧道,并根据每个请求的性质切换行为。

         >             >             >             >

    UA =========== A =========== B =========== C =========== O

                <             <             <             <

上图显示了用户代理与 源服务器之间的三个中间方(A、B 和 C)。遍历整个链的请求或响应消息将通过 四个独立的连接。某些 HTTP 通信选项可能仅适用于 与最近的非隧道邻居之间的连接、仅适用于 链的端点,或者适用于链上的所有连接。尽管该图是线性的,但每个 参与者都可能同时参与多个通信。例如,B 可能正在接收来自 A 以外多个客户端的请求,和/或将请求转发 到 C 以外的服务器,同时它也在处理 A 的请求。同样, 后续请求可能会通过不同的连接路径发送,通常基于 用于负载均衡的动态配置。

术语 上游和下游用于描述与消息流有关的方向性 要求:所有消息都从上游流向 下游。术语入站和出站用于描述 与请求路由有关的方向性要求:入站表示“朝向 源服务器”,而出站表示“朝向用户代理”。

代理是由 客户端选择(通常通过本地配置规则)来接收某些类型 的绝对 URI 请求,并尝试通过 HTTP 接口进行转换 以满足这些请求的消息转发代理。一些转换非常简单,例如针对 “http”URI 的代理请求,而其他请求可能需要在完全 不同的应用层协议之间进行转换。代理通常用于将组织的 HTTP 请求集中通过一个公共中间方,以提供安全服务、 注释服务或共享缓存。一些代理被设计为在转发过程中对选定的 消息或内容应用转换,如 第 7.7 节所述。

网关(又称反向代理)是 一个针对出站连接充当源服务器,但会转换 收到的请求并将其向入站方向转发给另一个或多个服务器的中间方。网关 通常用于封装旧式或不受信任的信息服务,通过加速器缓存提高服务器 性能,并支持跨多台机器对 HTTP 服务进行分区或负载 均衡。

适用于源服务器的所有 HTTP 要求也适用于网关的出站 通信。网关使用其所需的任何 协议与入站服务器通信,包括超出本 规范范围的 HTTP 私有扩展。但是,希望 与第三方 HTTP 服务器互操作的 HTTP 到 HTTP 网关需要在 网关的入站连接上符合用户代理要求。

隧道在两个 连接之间充当盲中继,而不更改消息。一旦激活,隧道不被视为 HTTP 通信的一方,尽管隧道可能是由 HTTP 请求发起的。当中继连接的两端均关闭时,隧道便不复存在。 隧道用于通过中间方扩展虚拟连接,例如当 传输层安全性(TLS,[TLS13]) 用于通过共享防火墙代理建立机密通信时。

上述中间方类别仅考虑那些作为 HTTP 通信参与者的中间方。还有一些中间方可以在 网络协议栈的较低层运行,在消息发送方不知情或 未经其许可的情况下过滤或重定向 HTTP 流量。网络中间方在 协议层面与路径上的攻击者无法区分,通常会由于错误地违反 HTTP 语义而引入安全缺陷或 互操作性问题。

例如, 拦截代理 [RFC3040](也 通常称为透明代理 [RFC1919])不同于 HTTP 代理,因为它不是由客户端选择的。相反,拦截 代理会过滤或重定向传出的 TCP 端口 80 数据包(有时也包括其他常见 端口流量)。拦截代理常见于公共网络接入点, 用于在允许使用非本地 Internet 服务之前强制执行账户订阅要求,也用于企业防火墙中执行网络使用策略。

3.8. 缓存

缓存是先前响应消息的本地存储,以及控制其 消息存储、检索和删除的子系统。缓存会存储可缓存的 响应,以减少未来等效请求的响应时间和网络带宽 消耗。任何客户端或服务器都可以使用 缓存,但在充当隧道时不能使用缓存。

缓存的效果是,如果链中的某个 参与者具有适用于该请求的缓存响应,则请求/响应链会缩短。下图 展示了如果 B 缓存了来自 O(经由 C)的某个早期响应的副本, 而对应请求尚未被 UA 或 A 缓存时所得的链。

            >             >

        UA =========== A =========== B - - - - - - C - - - - - - O

                   <             <

如果允许缓存存储响应消息的 副本,以用于回答后续请求,则响应是可缓存的。即使 响应是可缓存的,客户端或源服务器也可能对该缓存响应何时可以用于特定 请求施加额外限制。HTTP 对缓存行为和可缓存响应的要求定义于 [CACHING]。

万维网和大型组织内部部署了各种各样的缓存架构和配置 。其中包括用于节省带宽并减少延迟的全国性 代理缓存层次结构、使用 网关缓存优化热门站点区域和全球分发的内容分发网络、 广播或多播缓存条目的协作系统、为离线或高延迟环境预取 缓存条目的存档,等等。

3.9. 示例 消息交换

以下示例说明了针对 URI 上 GET 请求的典型 HTTP/1.1 消息交换 (第 9.3.1 节) "http://www.example.com/hello.txt":

客户端请求:

GET /hello.txt HTTP/1.1

User-Agent: curl/7.64.1

Host: www.example.com

Accept-Language: en, mi



服务器响应:

HTTP/1.1 200 OK

Date: Mon, 27 Jul 2009 12:28:53 GMT

Server: Apache

Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT

ETag: "34aa387-d-1568eb00"

Accept-Ranges: bytes

Content-Length: 51

Vary: Accept-Encoding

Content-Type: text/plain



Hello World! My content includes a trailing CRLF.

4. HTTP 中的标识符

统一资源标识符 (URI) [URI] 在 整个 HTTP 中用作标识资源的手段(第 3.1 节)。

4.1. URI 引用

URI 引用用于指定请求目标、指示重定向以及定义关系。

“URI-reference”、“absolute-URI”、“relative-part”、“authority”、“port”、 “host”、“path-abempty”、“segment”和“query”的定义采用 URI 通用语法中的定义。 对于能够包含非空路径组件的协议元素,定义了“absolute-path” 规则。(此规则与 RFC 3986 的 path-abempty 规则略有不同, 后者允许空路径;也与 path-absolute 规则不同,后者不允许以 “//”开头的路径。)对于可以包含相对 URI 但不能包含片段组件的协议元素,定义了“partial-URI”规则。

  URI-reference = <URI-reference, see [URI], Section 4.1>
  absolute-URI  = <absolute-URI, see [URI], Section 4.3>
  relative-part = <relative-part, see [URI], Section 4.2>
  authority     = <authority, see [URI], Section 3.2>
  uri-host      = <host, see [URI], Section 3.2.2>
  port          = <port, see [URI], Section 3.2.3>
  path-abempty  = <path-abempty, see [URI], Section 3.3>
  segment       = <segment, see [URI], Section 3.3>
  query         = <query, see [URI], Section 3.4>

  absolute-path = 1*( "/" segment )
  partial-URI   = relative-part [ "?" query ]

HTTP 中允许 URI 引用的每个协议元素都会在其 ABNF 产生式中指明该元素是允许任意形式的引用 (URI-reference)、仅允许绝对形式的 URI (absolute-URI)、仅允许路径和可选查询组件 (partial-URI),还是上述形式的某种组合。除非另有说明,URI 引用相对于目标 URI(第 7.1 节)进行解析。

推荐所有发送方和接收方至少支持 协议元素中长度为 8000 个八位字节的 URI。请注意,这意味着 某些结构和在线路上的表示(例如 HTTP/1.1 中的请求行) 在某些情况下必然会更大。

4.2. HTTP 相关的 URI 方案

IANA 在 https://www.iana.org/assignments/uri-schemes/ 维护 URI 方案注册表 [BCP35]。 尽管请求可以将任意 URI 方案作为目标,但以下方案是 HTTP 服务器固有的:

表 2
URI 方案 说明 章节
http 超文本传输协议 4.2.1
https 安全超文本传输协议 4.2.2

请注意,“http”或“https”URI 的存在并不意味着所标识的源上始终有 HTTP 服务器正在监听连接。任何人都可以创建 URI, 无论服务器是否存在,也无论该服务器当前是否将该 标识符映射到资源。注册名称和 IP 地址的委派性质 会形成一个联合命名空间,无论 HTTP 服务器是否存在。

4.2.1. http URI 方案

“http”URI 方案在此定义为用于在 由潜在 HTTP 源服务器管理的分层命名空间中创建标识符,该服务器在给定端口上监听 TCP ([TCP])连接。

  http-URI = "http" "://" authority path-abempty [ "?" query ]

“http”URI 的源服务器由 authority 组件标识,其中包含主机标识符([URI], 第 3.2.2 节)和可选的端口号([URI], 第 3.2.3 节)。如果端口子组件为空或未给出,则默认为 TCP 端口 80( 为 WWW 服务保留的端口)。源决定谁有权对以所标识资源为目标的请求作出权威响应,如 第 4.3.2 节所定义。

发送方不得生成主机 标识符为空的“http”URI。处理此类 URI 引用的接收方必须将其作为无效内容拒绝。

分层路径组件和可选查询组件标识该源 服务器命名空间中的目标资源。

4.2.2. https URI 方案

“https”URI 方案在此定义为用于在 由潜在源服务器管理的分层命名空间中创建标识符,该服务器在给定端口上监听 TCP 连接,并且能够建立一个为 HTTP 通信提供安全保护的 TLS([TLS13]) 连接。在此上下文中, 受保护的明确表示服务器已经通过身份验证,被确认代表所标识的权威方行事,并且与该 服务器之间的所有 HTTP 通信都具有客户端和服务器双方可接受的 机密性和完整性保护。

  https-URI = "https" "://" authority path-abempty [ "?" query ]

“https”URI 的源服务器由 authority 组件标识,其中包含主机标识符([URI], 第 3.2.2 节)和可选的端口号([URI], 第 3.2.3 节)。如果端口子组件为空或未给出,则默认为 TCP 端口 443( 为基于 TLS 的 HTTP 保留的端口)。源决定谁有权对以所标识资源为目标的请求作出权威响应,如 第 4.3.3 节所定义。

发送方不得生成主机 标识符为空的“https”URI。处理此类 URI 引用的接收方必须将其作为无效内容拒绝。

分层路径组件和可选查询组件标识该源 服务器命名空间中的目标资源。

客户端必须确保其针对“https” 资源的 HTTP 请求在传输之前受到安全保护,并且只接受对这些请求的受保护 响应。请注意,客户端和服务器可接受的加密 机制的定义通常通过协商确定,并可能随 时间变化。

通过“https”方案提供的资源与 “http”方案不共享身份。它们是具有独立命名空间的不同源。但是, 定义为适用于具有相同主机的所有源的 HTTP 扩展, 例如 Cookie 协议 [COOKIE],允许 一个服务设置的信息影响与匹配 主机域组中的其他服务的通信。此类扩展应当非常谨慎地设计, 以防止从受保护连接获得的信息被无意中 交换到不安全的上下文中。

4.2.3. http(s) 规范化和比较

具有“http”或“https”方案的 URI 按照 第 6 节中 [URI] 所定义的方法进行规范化和比较,并使用上述每个方案的默认值。

HTTP 不要求使用特定方法来确定等价性。例如, 缓存键可以在基于语法 规范化后,或基于方案规范化后,作为简单字符串进行比较。

“http”和“https”URI 的基于方案的规范化( [URI] 的第 6.2.3 节) 涉及以下附加规则:

  • 如果端口等于某方案的默认端口,则规范形式是 省略端口子组件。
  • 当未用作 OPTIONS 请求的目标时,空路径组件 等价于绝对路径“/”,因此规范形式是改为提供 路径“/”。
  • 方案和主机不区分大小写,通常以小写形式提供;所有 其他组件均以区分大小写的方式进行比较。
  • 除“保留”集合中的字符外,其他字符都等价于其 百分号编码的八位字节:规范形式是不对它们进行编码(参见 2.1 和 2.2 节,见 [URI])。

例如,以下三个 URI 是等价的:

   http://example.com:80/~smith/home.html
   http://EXAMPLE.com/%7Esmith/home.html
   http://EXAMPLE.com:/%7esmith/home.html

规范化后(使用任意方法)等价的两个 HTTP URI 可以被 认为标识同一资源,并且任何 HTTP 组件都可以执行规范化。因此,不同的资源 不应该由规范化后等价的 HTTP URI 标识(使用 第 6.2 节 中 [URI] 定义的任意方法)。

4.2.4. 弃用 http(s) URI 中的 userinfo

authority 的 URI 通用语法还包含 userinfo 子组件([URI], 第 3.2.1 节),用于在 URI 中包含用户身份验证信息。在该 子组件中,“user:password”格式的使用已被弃用。

某些实现使用 userinfo 组件在内部配置 身份验证信息,例如在命令调用选项、配置 文件或书签列表中,即使这种用法可能会暴露用户标识符或 密码。

当在消息中生成“http”或“https”URI 引用 作为目标 URI 或字段值时,发送方不得生成 userinfo 子组件(及其 “@”分隔符)。

在使用从不受信任的 来源收到的“http”或“https”URI 引用之前,接收方应该解析 userinfo,并将其 存在视为错误;它很可能被用于隐藏权威方,以实施 网络钓鱼攻击。

4.2.5. 带片段标识符的 http(s) 引用

片段标识符允许间接标识次级资源, 与 URI 方案无关,如 第 3.5 节 中 [URI] 所定义。 某些引用 URI 的协议元素允许包含片段,而 另一些则不允许。允许片段的元素通过使用相应的 ABNF 规则加以区分; 否则使用明确排除片段的特定规则。

4.3. 权威访问

权威访问是指为了访问 所标识的资源,以客户端认为具有权威性 (由资源所有者控制)的方式对给定标识符进行解引用。确定是否允许访问的过程 由 URI 方案定义,并且通常使用 URI 组件中的数据,例如 使用通用语法时的 authority 组件。但是,权威 访问并不限于所标识的机制。

第 4.3.1 节定义了源的概念, 以辅助此类使用,后续小节说明如何确定 对等方具有代表某个源的权威性。

有关建立权威性相关的安全考虑,请参见 第 17.1 节。

4.3.1. URI 源

给定 URI 的源是方案、主机和端口组成的三元组,在 将方案和主机规范化为小写,并将端口规范化以删除任何 前导零之后得到。如果 URI 中省略端口,则使用该方案的默认端口 。例如,URI

   https://Example.Com/happy.js

将具有源

   { "https", "example.com", "443" }

也可以描述为始终包含端口的规范化 URI 前缀:

   https://example.com:443

每个源定义自己的命名空间,并控制该 命名空间中的标识符如何映射到资源。反过来,源如何对有效 请求作出长期一致的响应,决定了用户将与 URI 关联的语义,而这些语义的实用性最终会将 这些机制转化为供用户未来引用和访问的资源。

如果两个源在方案、主机或端口上不同,则它们是不同的。即使可以 验证同一实体控制两个不同的源,这两个源下的命名空间 仍然不同,除非由对该源具有权威性的服务器明确建立 别名。

源这一概念也用于 HTML 和相关 Web 协议中,这超出了本文的 范围,如 [RFC6454]所述。

4.3.2. http 源

尽管 HTTP 独立于传输协议,但“http”方案(第 4.2.1 节)专门用于 将权威性与控制源服务器的一方关联起来,该服务器在 authority 组件中标识的主机所指定的端口上监听 TCP 连接。这是一种非常弱的权威性,因为它依赖于 客户端特定的名称解析机制以及可能无法防范 路径上攻击者的通信。尽管如此,对于 在受信任环境中将“http”标识符绑定到源服务器并保持一致解析而言,这已经是足够的最低要求。

如果主机标识符以 IP 地址形式提供,则源服务器是该 IP 地址 上所指示 TCP 端口的监听程序(如果存在)。如果 host 是 注册名称,则该注册名称是供名称 解析服务(例如 DNS)使用的间接标识符,用于查找适当源 服务器的地址。

当“http”URI 用于需要访问所指示 资源的上下文中时,客户端可以通过将主机 标识符解析为 IP 地址、在所指示端口上与该地址建立 TCP 连接,并通过该 连接发送包含与客户端目标 URI 匹配的 请求目标的 HTTP 请求消息来尝试访问(第 7.1 节)。

如果服务器对此类请求以非临时 HTTP 响应消息作出响应,如 第 15 节所述,则该 响应被视为对客户端请求的权威回答。

但是请注意,上述方式并不是获得权威 响应的唯一方式,也不意味着始终需要权威响应(参见 [CACHING])。例如,Alt-Svc 头 字段 [ALTSVC] 允许源 服务器标识同样对该源具有权威性的其他服务。 对“http”所标识资源的访问也可能由本文 范围之外的协议提供。

4.3.3. https 源

“https”方案(第 4.2.2 节) 根据服务器使用与客户端认为对于所标识 源服务器可信的证书相对应的私钥的能力来关联权威性。客户端通常依赖 从某个预先安排或配置的信任锚传递而来的信任链, 来认定证书可信 (第 4.3.4 节)。

在 HTTP/1.1 及更早版本中,只有当客户端与服务器 通过专门连接到该 URI 源主机的、成功建立并受到保护的连接 进行通信时,客户端才会将权威性赋予服务器。连接建立和证书 验证被用作权威性的证明。

在 HTTP/2 和 HTTP/3 中,如果客户端与服务器通过 成功建立并受到保护的连接进行通信,并且 URI 源的主机与服务器证书中存在的任一主机匹配,且 客户端认为它能够为该 URI 建立到该主机的连接,则客户端会将权威性赋予服务器。实际 上,客户端会进行 DNS 查询,以检查源的主机是否包含 与已建立连接相同的服务器 IP 地址。源服务器可以通过发送等效的 ORIGIN 帧 [RFC8336]来移除此限制。

请求目标的主机和端口值会在每个 HTTP 请求中传递, 用于标识源,并将其与可能由 同一服务器控制的其他命名空间区分开来(第 7.2 节)。源有责任 确保任何被赋予其证书私钥控制权的服务 同样负责管理相应的“https”命名空间,或者至少 准备拒绝看起来被错误定向的请求(第 7.4 节)。

即使源服务器有权处理某些目标 URI 的请求,它也可能不愿意 处理这些请求。例如,当主机在不同端口(例如 443 和 8000)上运行不同 服务时,有必要在 源服务器检查目标 URI(即使连接已经受到保护),因为 网络攻击者可能导致针对一个端口的连接被其他 端口接收。如果不检查目标 URI,则此类攻击者可能能够用来自另一端口 (例如“https://example.com:8000/foo”)看似具有 权威性的响应替换对某个目标 URI(例如“https://example.com/foo”)的响应。

请注意,“https”方案并不依赖 TCP 和已连接的端口号来 关联权威性,因为二者都位于受保护通信之外,因此 不能作为确定依据而受到信任。因此,HTTP 通信可以通过 任何已受到保护的信道进行,如 第 4.2.2 节所定义,包括不使用 TCP 的协议。

当“https”URI 用于需要访问所指示 资源的上下文中时,客户端可以通过将主机 标识符解析为 IP 地址、在所指示端口上与该地址建立 TCP 连接、 通过 TCP 成功启动具有机密性和完整性保护的 TLS 来对连接进行端到端保护,并通过该 连接发送包含与 客户端目标 URI 匹配的请求目标的 HTTP 请求消息(第 7.1 节),从而尝试访问。

如果服务器对此类请求以非临时 HTTP 响应消息作出响应,如 第 15 节所述,则该 响应被视为对客户端请求的权威回答。

但是请注意,上述方式并不是获得权威 响应的唯一方式,也不意味着始终需要权威响应(参见 [CACHING])。

4.3.4. https 证书验证

为了建立用于解引用 URI 的受保护连接, 客户端必须验证服务的 身份是否与 URI 的源服务器可接受地匹配。证书 验证用于防止路径上的攻击者或控制 名称解析的攻击者冒充服务器。此过程要求客户端 配置一组信任锚。

通常,客户端必须使用 第 6 节中 [RFC6125] 所定义的验证过程来验证服务身份。 客户端必须根据服务的 host 构造引用身份: 如果 host 是 IP 地址字面量(第 4.3.5 节),则引用身份为 IP-ID;否则 host 是名称,引用身份为 DNS-ID。

客户端不得使用 CN-ID 类型的引用身份。 如 第 6.2.1 节中 [RFC6125] 所指出,旧版客户端可能使用 CN-ID 类型的引用身份。

客户端可能经过特殊配置,以接受其他形式的服务器 身份验证。例如,客户端可能连接到一个 地址和主机名都是动态的服务器,同时预期该服务将提供 特定证书(或与某个外部定义的引用 身份匹配的证书),而不是与目标 URI 的源匹配的证书。

在特殊情况下,客户端直接忽略服务器 身份可能是合适的,但必须明白,这会使连接暴露于主动 攻击。

如果证书对目标 URI 的源无效,则用户代理必须在继续之前获得用户确认 (参见 第 3.5 节),或者 以错误证书错误终止连接。自动客户端必须将错误记录到适当的审计日志(如果可用), 并且应该终止连接(并报告错误证书 错误)。自动客户端可以提供禁用此检查的配置设置, 但必须提供一个能够 启用该检查的设置。

4.3.5. IP-ID 引用身份

在“https”URI 的“host”字段中使用 IP 地址字面量标识的服务器 具有 IP-ID 类型的引用身份。IP 版本 4 地址使用 “IPv4address”ABNF 规则,而 IP 版本 6 地址使用带有 “IPv6address”选项的“IP-literal”产生式;参见 第 3.2.2 节,见 [URI]。 IP-ID 类型的引用身份包含 IP 地址解码后的字节。

IP 版本 4 地址为 4 个八位字节,IP 版本 6 地址为 16 个八位字节。 IP-ID 未针对任何其他 IP 版本定义。证书 subjectAltName 扩展中的 iPAddress 选项没有明确包含 IP 版本,因此 依赖地址长度来区分版本;参见 第 4.2.1.6 节,见 [RFC5280]。

如果地址与证书 subjectAltName 扩展中的 iPAddress 值完全相同,则 IP-ID 类型的引用身份匹配。

5. 字段

HTTP 使用字段以可扩展名称/值对的形式提供数据,并具有 已注册的键命名空间。字段在消息的头部和尾部 部分中发送和接收(第 6 节)。

5.1. 字段 名称

字段名称表示相应字段值具有该 名称所定义的语义。例如,Date 头字段 在 第 6.6.1 节中定义为包含其所在消息的生成时间戳。

字段名称不区分大小写,并且应当注册在“超文本 传输协议 (HTTP) 字段名称注册表”中;参见 第 16.3.1 节。

字段的解释在同一 HTTP 主版本的不同次版本之间不会改变, 尽管在缺少该字段时接收方的默认行为 可能改变。除非另有规定,否则字段为所有 HTTP 版本定义。特别 是,无论 HTTP 实现是否声明符合 HTTP/1.1,都应当识别 Host 和 Connection 字段。

如果新字段定义的语义允许无法识别它们的接收方安全地忽略它们, 则可以在不更改协议版本的情况下引入新字段;参见 第 16.3 节。

代理必须转发无法识别的头字段,除非该字段 名称列在 Connection 头 字段中(第 7.6.1 节),或者代理被专门配置为 阻止或以其他方式转换此类字段。其他接收方应该忽略无法识别的头字段和尾部字段。遵守 这些要求可以在无需更新或 移除已部署中间方的情况下扩展 HTTP 的功能。

5.2. 字段 行和组合字段值

字段部分由任意数量的字段 行组成,每一行都有一个用于标识字段的字段名称(参见 第 5.1 节),以及一个传达该字段实例数据的字段行 值。

当某个字段名称在一个部分中仅出现一次时,该字段的 组合字段值由相应字段行 值组成。当某个字段名称在一个部分中重复出现时,其组合字段值由 该部分中相应字段行值组成的列表构成,并按 顺序连接,每个字段行值之间用逗号分隔。

例如,此部分:

Example-Field: Foo, Bar
Example-Field: Baz

包含两个字段行,两者的字段名称都是“Example-Field”。第一个字段行 的字段行值是“Foo, Bar”,第二个字段行值是“Baz”。 “Example-Field”的字段值是列表“Foo, Bar, Baz”。

5.3. 字段 顺序

接收方可以将字段部分中具有相同字段名称的多个字段行 合并为一个字段行,而不改变 消息的语义,方法是按顺序将每个后续字段行值追加到初始 字段行值,并使用逗号 (",") 和可选空白(OWS,定义见 第 5.6.3 节)分隔。为保持一致,请使用逗号 SP。

因此,具有相同名称的字段行的接收顺序对于 字段值的解释很重要;代理不得在转发消息时改变 这些字段行值的顺序。

这意味着,除了下文所述的众所周知例外之外,发送方不得在一条 消息中(无论是在头部还是尾部)生成多个同名字段行,或者在消息中已存在 同名字段行时追加字段行,除非该字段的定义允许 将多个字段行值重新组合成逗号分隔列表(即字段定义中至少 一个替代形式允许逗号分隔列表,例如 第 5.6.1 节中定义的 #(values) ABNF 规则)。

一个部分中不同字段名称的字段行的接收顺序 并不重要。但是,最好首先发送包含 附加控制数据的头字段,例如请求中的 Host 和 响应中的 Date,以便 实现能够尽早决定何时不处理消息。

服务器在收到完整的请求头部分之前不得将请求应用于目标资源,因为后续头字段行可能包含 条件、身份验证凭据或故意误导的重复头 字段,这些都可能影响请求处理。

5.4. 字段 限制

HTTP 不会预先限制每个字段行、字段值的长度, 也不会限制整个头部或尾部部分的长度,如 第 2 节所述。实际中可以看到针对 各个长度的各种临时限制,通常取决于特定字段的 语义。

如果服务器收到的请求头字段行、字段值或字段集合大于 它希望处理的大小,则必须以适当的 4xx(客户端错误)状态码响应。忽略此类 头字段会增加服务器遭受请求走私攻击的风险(第 11.2 节,见 [HTTP/1.1])。

如果字段语义允许安全地忽略 被丢弃的值而不改变消息分帧或响应 语义,则客户端可以丢弃或截断大于客户端希望处理大小的已接收字段行。

5.5. 字段 值

HTTP 字段值由按照字段 语法所定义格式排列的字符序列组成。每个字段的语法通常使用 ABNF 定义([RFC5234])。

字段值不包括前导或尾随空白。当某个特定 HTTP 版本允许此类空白出现在消息中时,字段解析实现必须在对字段值求值之前排除此类空白。

字段值通常限制在 US-ASCII 字符范围内 [USASCII]。 需要更大字符范围的字段可以使用编码,例如 [RFC8187]中定义的编码。 从历史上看,HTTP 允许字段内容包含 ISO-8859-1 字符集 [ISO-8859-1]中的文本, 其他字符集只能通过使用 [RFC2047] 编码来支持。新定义字段的规范应该将 其值限制为可见 US-ASCII 八位字节 (VCHAR)、SP 和 HTAB。接收方应该将字段内容中其他允许的八位字节(即 obs-text)作为不透明数据处理。

包含 CR、LF 或 NUL 字符的字段值无效且危险,这是由于 实现解析和解释这些字符的方式各不相同;字段值中包含 CR、LF 或 NUL 的接收方必须拒绝 消息,或者在进一步处理 或转发该消息之前将这些字符逐一替换为 SP。包含其他 CTL 字符的字段值同样 无效;但是,当这些字符出现在安全上下文中时(例如,不会由任何下游 HTTP 解析器处理的应用特定 引号字符串),接收方可以为提高健壮性而保留此类字符。

仅预期字段 值包含单个成员的字段称为单值字段。

允许字段值包含多个成员的字段 称为基于列表的字段。第 5.6.1 节的列表运算符扩展 用作定义可包含多个成员的字段值的通用表示法。

由于逗号 (",") 用作成员之间的分隔符,如果逗号允许作为成员中的数据, 就需要谨慎处理。无论对于基于列表的 字段还是单值字段都是如此,因为单值字段可能被错误地以多个 成员发送,而检测这种错误可以提高互操作性。预期 在成员中包含逗号的字段,例如在 HTTP-date 或 URI-reference 元素中,应当在该 元素周围定义分隔符,以区分数据中的逗号和潜在的列表分隔符。

例如,文本日期和 URI(两者都可能包含逗号)可以像下面这样 安全地包含在基于列表的字段值中:

Example-URIs: "http://example.com/a.html,foo",
              "http://without-a-comma.example.com/"
Example-Dates: "Sat, 04 May 1996", "Wed, 14 Sep 2005"

请注意,双引号分隔符几乎总是与 quoted-string 产生式(第 5.6.4 节)一起使用;在 双引号内使用不同语法很可能造成不必要的混淆。

许多字段(例如 Content-Type,定义 于 第 8.3 节)使用通用参数语法,该语法允许 参数值使用不带引号的 (token) 和带引号的 (quoted-string) 两种语法(第 5.6.6 节)。使用通用语法可以让 接收方复用现有解析器组件。当允许两种形式时,无论参数值是作为 token 还是带引号 字符串接收,其含义都应当相同。

5.6. 定义字段值的通用规则

5.6.1. 列表(#rule ABNF 扩展)

对 [RFC5234] 的 ABNF 规则使用 #rule 扩展,以提高某些基于列表的字段值定义的可读性。

定义了类似于“*”的“#”构造,用于定义以逗号分隔的 元素列表。完整形式是“<n>#<m>element”,表示至少 <n> 个、至多 <m> 个元素,每个元素由单个逗号 (",") 和 可选空白(OWS,定义见 第 5.6.3 节)分隔。

5.6.1.1. 发送方要求

在使用列表构造的任何产生式中,发送方不得 生成空列表元素。换言之,发送方必须 生成满足以下语法的列表:

  1#element => element *( OWS "," OWS element )

以及:

  #element => [ 1#element ]

对于 n >= 1 且 m > 1:

  <n>#<m>element => element <n-1>*<m-1>( OWS "," OWS element )

附录 A展示了 展开列表构造后发送方使用的汇总 ABNF。

5.6.1.2. 接收方要求

空元素不计入存在的元素数量。接收方 必须解析并忽略合理数量的空列表 元素:数量应足以处理发送方合并值时的常见错误,但不能 多到可被用作拒绝服务机制。换 言之,接收方必须接受满足 以下语法的列表:

  #element => [ element ] *( OWS "," OWS [ element ] )

请注意,由于可能存在空列表元素,RFC 5234 ABNF 无法强制列表元素的基数,因此所有情况 都按未指定基数来映射。

例如,给定以下 ABNF 产生式:

  example-list      = 1#example-list-elmt
  example-list-elmt = token ; 参见 第 5.6.2 节

那么以下是 example-list 的有效值(不包括双 引号,它们仅用于分隔):

  "foo,bar"
  "foo ,bar,"
  "foo , ,bar,charlie"

相比之下,以下值无效,因为 example-list 产生式要求至少一个非空 元素:

  ""
  ","
  ",   ,"

5.6.2. 令牌

令牌是不包含 空白或分隔符的短文本标识符。

  token          = 1*tchar

  tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                 / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                 / DIGIT / ALPHA
                 ; 除分隔符外的任意 VCHAR

许多 HTTP 字段值使用 通用语法组件定义,并由空白或特定分隔 字符分隔。分隔符从不允许出现在 token 中的 US-ASCII 可见字符集合中选择(DQUOTE 和 "(),/:;<=>?@[\]{}")。

5.6.3. 空白

本规范使用三条规则表示线性空白的使用:OWS (可选空白)、RWS(必需空白)和 BWS(“不良”空白)。

OWS 规则用于可能出现零个或多个线性空白八位字节的位置。对于 为提高可读性而倾向使用可选空白的协议元素, 发送方应该将可选空白生成为单个 SP;否则,发送方不应该生成可选 空白,除非在原地消息过滤期间需要覆盖无效或不需要的协议元素。

当至少需要一个线性空白八位字节来 分隔字段令牌时使用 RWS 规则。发送方应该将 RWS 生成为 单个 SP。

OWS 和 RWS 与单个 SP 具有相同语义。任何已知定义为 OWS 或 RWS 的内容在解释或将消息向下游转发之前可以替换为单个 SP。

BWS 规则用于语法仅出于历史 原因允许可选空白的位置。发送方不得在消息中生成 BWS。 接收方必须解析此类不良空白,并在 解释协议元素之前将其删除。

BWS 没有语义。任何已知定义为 BWS 的内容在解释或将 消息向下游转发之前都可以删除。

  OWS            = *( SP / HTAB )
                 ; 可选空白
  RWS            = 1*( SP / HTAB )
                 ; 必需空白
  BWS            = OWS
                 ; “不良”空白

5.6.4. 带引号的字符串

如果文本字符串使用双引号 括起,则会将其解析为单个值。

  quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE
  qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text

反斜杠八位字节 ("\") 可以在 quoted-string 和 comment 构造中用作单八位字节引用 机制。处理 quoted-string 值的接收方必须像 quoted-pair 被替换为反斜杠之后的八位字节那样进行处理。

  quoted-pair    = "\" ( HTAB / SP / VCHAR / obs-text )

除非为了引用字符串中出现的 DQUOTE 和反斜杠八位字节所必需, 否则发送方不应该在 quoted-string 中生成 quoted-pair 。除非为了引用注释中出现的圆括号 ["(" 和 ")"] 和反斜杠 八位字节所必需,否则发送方不应该在 comment 中生成 quoted-pair。

5.6.5. 注释

某些 HTTP 字段可以通过用圆括号包围 注释文本来包含注释。只有字段值定义中包含 “comment”的字段才允许使用注释。

  comment        = "(" *( ctext / quoted-pair / comment ) ")"
  ctext          = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text

5.6.6. 参数

参数是名称/值对的实例;它们通常在字段值中用作 向项目附加辅助信息的通用语法。 每个参数通常由紧邻其前的分号分隔。

参数名称不区分大小写。参数值可能区分大小写,也可能不区分, 具体取决于参数名称的语义。参数及其一些等价形式的示例 可以在媒体类型(第 8.3.1 节)和 Accept 头 字段(第 12.5.1 节)中看到。

匹配 token 产生式的参数值既可以作为 token 传输,也可以放在 quoted-string 中传输。带引号和不带引号的值是等价的。

5.6.7. 日期/时间格式

1995 年以前,服务器通常使用三种不同的格式来 传达时间戳。为了与旧实现兼容,这三种格式都在 此处定义。首选格式是 Internet 消息格式 [RFC5322]所使用日期和时间规范的固定长度、单时区子集。

首选格式的一个示例是

Sun, 06 Nov 1994 08:49:37 GMT    ; IMF-fixdate

两种废弃格式的示例如下

Sunday, 06-Nov-94 08:49:37 GMT   ; 废弃的 RFC 850 格式
Sun Nov  6 08:49:37 1994         ; ANSI C 的 asctime() 格式

解析 HTTP 字段中时间戳值的接收方必须接受所有三种 HTTP-date 格式。当发送方 生成包含一个或多个定义为 HTTP-date 的时间戳的字段时, 发送方必须以 IMF-fixdate 格式生成这些时间戳。

HTTP-date 值将时间表示为协调世界时 (UTC) 的一个时刻。前两种格式使用 格林尼治标准时间的三字母缩写“GMT”来表示 UTC,GMT 是 UTC 名称的前身;asctime 格式中的值被假定为 UTC。

时钟是能够提供当前 UTC 时刻合理 近似值的实现。时钟实现应当使用 NTP ([RFC5905]), 或类似协议,与 UTC 同步。

首选格式:

  IMF-fixdate  = day-name "," SP date1 SP time-of-day SP GMT
  ; 该格式的固定长度/时区/大小写子集
  ; 参见 [RFC5322] 的第 3.3 节

  day-name     = %s"Mon" / %s"Tue" / %s"Wed"
               / %s"Thu" / %s"Fri" / %s"Sat" / %s"Sun"

  date1        = day SP month SP year
               ; 例如,02 Jun 1982

  day          = 2DIGIT
  month        = %s"Jan" / %s"Feb" / %s"Mar" / %s"Apr"
               / %s"May" / %s"Jun" / %s"Jul" / %s"Aug"
               / %s"Sep" / %s"Oct" / %s"Nov" / %s"Dec"
  year         = 4DIGIT

  GMT          = %s"GMT"

  time-of-day  = hour ":" minute ":" second
               ; 00:00:00 - 23:59:60(闰秒)

  hour         = 2DIGIT
  minute       = 2DIGIT
  second       = 2DIGIT

废弃格式:

  rfc850-date  = day-name-l "," SP date2 SP time-of-day SP GMT
  date2        = day "-" month "-" 2DIGIT
               ; 例如,02-Jun-82

  day-name-l   = %s"Monday" / %s"Tuesday" / %s"Wednesday"
               / %s"Thursday" / %s"Friday" / %s"Saturday"
               / %s"Sunday"
  asctime-date = day-name SP date3 SP time-of-day SP year
  date3        = month SP ( 2DIGIT / ( SP 1DIGIT ))
               ; 例如,Jun  2

HTTP-date 区分大小写。请注意,第 4.2 节,见 [CACHING],针对缓存接收方放宽了 此要求。

发送方不得在 HTTP-date 中生成超出语法中明确包含为 SP 的额外空白。day-name、day、month、year 和 time-of-day 的语义与 Internet 消息格式中同名构造的定义相同([RFC5322],第 3.3 节)。

rfc850-date 格式的时间戳值使用两位数年份,其接收方 必须将看起来比未来超过 50 年的时间戳解释为过去最近一个具有 相同末两位数字的年份。

除非字段定义另有限制,否则鼓励时间戳值的接收方在解析时间戳时保持健壮 。例如,消息有时会 从可能生成 Internet 消息格式定义的任意 日期和时间规范的非 HTTP 来源通过 HTTP 转发。

6. 消息 抽象

HTTP 的每个主要版本都定义了自己的消息通信语法。本节 基于这些消息特征、共同结构以及传达语义的能力的概括, 为 HTTP 消息定义了一种抽象数据类型。此抽象 用于定义独立于 HTTP 版本的发送方和接收方要求, 从而使一个版本中的消息可以通过其他版本中继,而不会 改变其含义。

消息由以下内容组成:

  • 用于描述和路由消息的控制数据,
  • 由名称/值对组成的 headers 查找表,用于扩展该控制数据并传达 有关发送方、消息、内容或上下文的附加信息,
  • 可能无界的内容流,以及
  • 由名称/值对组成的 trailers 查找表,用于传达 发送内容时获得的信息。

首先发送分帧和控制数据,随后是包含 headers 表字段的头部部分。当消息包含内容时,内容在头部 部分之后发送,之后可能跟随一个尾部部分,其中可能包含 trailers 表的字段。

消息应作为流处理,在读取过程中会逐步揭示该流的用途及其 后续处理方式。因此,控制数据描述接收方 立即需要知道的内容,头字段描述在 接收内容之前需要知道的内容,内容(如果存在)大概包含接收方为 实现消息语义而想要或需要的内容,而尾部字段则提供 在发送内容之前未知的可选元数据。

消息旨在是自描述的:接收方需要了解的 有关消息的一切,都可以通过查看消息本身来确定,只需对 传输过程中被压缩或省略的部分进行解码或重构,而无需 了解发送方当前的应用程序状态(由先前消息建立)。 但是,客户端在解析、 解释或缓存相应响应时必须保留对请求的了解。例如,对 HEAD 方法的响应看起来与 对 GET 的响应开头完全相同,但 不能以相同方式解析。

请注意,此消息抽象是对 HTTP 多个版本的概括, 包括某些版本中可能不存在的特性。例如,尾部字段最初在 HTTP/1.1 分块传输编码中作为内容之后的尾部部分引入。 HTTP/2 和 HTTP/3 中存在等效特性,它位于 终止每个流的头块中。

6.1. 分帧和完整性

消息分帧指示每条消息如何开始和结束,从而使每条消息都能 与同一连接上的其他消息或噪声区分开来。HTTP 的每个主要版本 都定义了自己的分帧机制。

HTTP/0.9 和 HTTP/1.0 的早期部署使用关闭底层连接的方式来 结束响应。为了向后兼容,HTTP/1.1 中也允许这种隐式分帧 。但是,如果连接提前关闭,隐式分帧可能无法区分不完整的响应 。因此,几乎所有现代实现都使用 以消息数据的长度分隔序列形式存在的显式分帧。

当其分帧所指示的所有八位字节均可用时,消息被视为完整的 。请注意,当未使用显式分帧时,由底层连接关闭而 结束的响应消息会被视为完整,即使它 可能无法与不完整响应区分,除非传输层错误 表明它并不完整。

6.2. 控制数据

消息以描述其主要用途的控制数据开始。请求消息 控制数据包括请求方法(第 9 节)、请求目标(第 7.1 节)和协议版本(第 2.5 节)。响应消息 控制数据包括状态码(第 15 节)、可选原因短语和协议版本。

在 HTTP/1.1([HTTP/1.1])及更早版本中,控制数据作为 消息的第一行发送。在 HTTP/2([HTTP/2])和 HTTP/3([HTTP/3])中,控制数据 作为具有保留名称前缀(例如“:authority”)的伪头字段发送。

每条 HTTP 消息都有协议版本。根据所使用的版本,它可能 在消息中被显式标识,或者根据接收 消息的连接推断出来。接收方使用该版本信息来确定 后续与该发送方通信的限制或可能性。

当消息由中间方转发时,会更新协议版本,以 反映该中间方所使用的版本。Via 头字段(第 7.6.3 节)用于在转发的消息中传达上游协议信息。

如果已知服务器支持的最高版本,则客户端应该发送与其符合的最高 版本相等、且主版本不高于 服务器所支持最高版本的请求版本。客户端不得发送其不符合的版本。

如果已知服务器错误地实现了 HTTP 规范,则客户端可以发送较低的请求版本, 但只有在客户端 至少尝试过一次正常请求,并根据响应状态码或 头字段(例如 Server)确定服务器 无法正确处理较高请求版本之后才能如此。

服务器应该发送其所符合的最高 版本作为响应版本,并且该版本的主版本应小于或等于 请求中接收到的主版本。服务器不得发送其 不符合的版本。如果服务器出于任何 原因希望拒绝为客户端的主协议版本提供服务,可以发送 505(不支持 HTTP 版本)响应。

接收方收到主版本号是其已实现版本、但 次版本号高于其已实现版本的消息时,应该 按照该主版本中接收方所符合的最高次版本 来处理该消息。接收方可以假定,当具有 较高次版本的消息发送给尚未表明支持 该较高版本的接收方时,它具有足够的向后兼容性,可以由 同一主版本的任何实现安全处理。

6.3. 头字段

在内容之前发送或接收的字段(第 5 节) 称为“头字段”(口语中也简称“headers”)。

消息的头部部分由一系列头字段行组成。 每个头字段都可以修改或扩展消息语义、描述发送方、定义 内容或提供附加上下文。

6.4. 内容

HTTP 消息通常将完整或部分表示作为消息 内容传输:由消息分帧界定、在头部部分之后发送的八位字节流 。

此内容的抽象定义反映从 消息分帧中提取后的数据。例如,HTTP/1.1 消息主体([HTTP/1.1] 的第 6 节) 可能由使用分块传输编码进行编码的数据流组成——一系列 数据块、一个零长度块和一个尾部部分——而 同一消息的内容仅包括传输编码被 解码后的数据流;它不包括块长度、分块分帧语法或尾部 字段(第 6.5 节)。

6.4.1. 内容语义

请求中内容的用途由方法语义(第 9 节)定义。

例如,PUT 请求内容中的表示(第 9.3.4 节)表示请求 成功应用后目标资源的期望状态 ,而 POST 请求内容中的表示 (第 9.3.3 节)表示 要由目标资源处理的信息。

在响应中,内容的用途由请求方法、响应 状态码(第 15 节)以及 描述该内容的响应字段定义。例如,对 GET(第 9.3.1 节)的 200 (OK) 响应的内容表示 在消息生成日期(第 6.6.1 节)时观察到的 目标资源当前状态,而 对 POST 的相同状态码响应的内容则可能表示处理 结果或应用处理后目标资源的新状态。

对 GET 的 206(部分内容) 响应的内容包含选定表示的单个部分,或者 包含该表示多个部分的多部分消息主体,如 第 15.3.7 节所述。

具有错误状态码的响应消息通常包含表示 错误状况的内容,因此该内容会描述错误状态以及建议采取哪些步骤 来解决该问题。

对 HEAD 请求方法(第 9.3.2 节)的响应绝不包含内容;相关响应 头字段仅指示如果请求方法 是 GET(第 9.3.1 节)时它们应具有的值。

对 CONNECT 请求方法(第 9.3.6 节)的 2xx(成功)响应 会将连接切换到隧道模式,而不是包含内容。

所有 1xx(信息性)、204(无内容)和 304 (未修改)响应都不包含内容。

所有其他响应都包含内容,尽管该内容的长度可能为零 。

6.4.2. 标识内容

当完整或部分表示作为消息内容传输时,通常 希望发送方提供,或者接收方确定,与该特定表示对应的 资源标识符。例如, 对“当前天气 报告”资源发出 GET 请求的客户端,可能希望得到专用于返回内容的标识符(例如“拉古纳海滩 20210720T1711 的天气报告”)。这对于分享或 为预期其表示会随时间变化的资源内容添加书签 很有用。

对于请求消息:

  • 如果请求具有 Content-Location 头字段,则发送方断言 该内容是由 Content-Location 字段值所标识资源的表示。但是,除非可以通过其他方式验证 (本规范未定义),否则不能信任这种断言。 此信息仍可能对修订历史链接有用。
  • 否则,HTTP 不标识该内容,但更具体的标识符 可能由内容本身提供。

对于响应消息,按顺序应用以下规则,直到找到 匹配项:

  1. 如果请求方法是 HEAD,或者响应状态码是 204(无内容)或 304(未修改),则响应中没有内容 。
  2. 如果请求方法是 GET 且响应状态码是 200 (OK),则内容是 目标 资源的表示(第 7.1 节)。
  3. 如果请求方法是 GET 且响应状态码是 203(非权威信息),则 内容是由中间方提供的目标资源的可能经过修改或增强的表示 。
  4. 如果请求方法是 GET 且响应状态码是 206(部分内容),则内容是 目标资源表示的一个或多个部分。
  5. 如果响应具有 Content-Location 头字段,并且其字段值是 对与目标 URI 相同 URI 的引用,则内容是 目标资源的表示。
  6. 如果响应具有 Content-Location 头字段,并且其字段值是 对不同于目标 URI 的 URI 的引用,则发送方断言 该内容是由 Content-Location 字段值所标识资源的表示。但是,除非可以通过其他方式验证 (本规范未定义),否则不能信任这种断言。
  7. 否则,HTTP 不标识该内容,但更具体的标识符 可能由内容本身提供。

6.5. 尾部字段

位于尾部部分中的字段(第 5 节) 称为“尾部字段”(口语中也简称“trailers”)。 尾部字段可用于提供消息完整性检查、 数字签名、传递指标或后处理状态信息。

尾部字段应当与头部 部分中的字段分开处理和存储,以避免与头部部分 完成时已知的消息语义相冲突。某些头字段是否存在可能会影响 在收到尾部字段之前对整个消息的路由或处理所作的选择; 后来发现尾部字段无法撤销这些选择。

6.5.1. 使用尾部字段的限制

只有当所使用的 HTTP 版本支持并且 显式分帧机制启用时,尾部部分才可能存在。例如,HTTP/1.1 中的分块传输编码 允许在内容之后发送尾部部分([HTTP/1.1] 的第 7.1.2 节)。

许多字段无法在头部部分之外处理,因为在接收内容之前 必须对它们进行求值,例如描述消息 分帧、路由、身份验证、请求修饰符、响应控制或内容 格式的字段。除非发送方知道相应头字段名称的定义允许该字段 在尾部中发送,否则发送方不得生成尾部字段。

对于将消息从一个协议版本转发到另一个协议版本的中间方而言, 尾部字段可能难以处理。如果整个消息可以在 传输过程中缓冲,某些中间方可以在转发之前将尾部字段合并到头部部分中(在 适当情况下)。但是,在大多数情况下,尾部字段会直接 被丢弃。除非接收方理解相应头字段 的定义,并且该定义明确允许并定义了如何安全合并尾部字段 值,否则接收方不得将尾部字段合并到 头部部分中。

请求的 TE 头字段(第 10.1.4 节)中存在关键词“trailers”,表示 客户端愿意代表自身以及任何 下游客户端接受尾部字段。对于来自中间方的请求,这意味着所有 下游客户端都愿意接受转发响应中的尾部字段。 请注意,“trailers”的存在并不意味着客户端会处理 响应中的任何特定尾部字段;它仅意味着尾部部分不会 被任何客户端丢弃。

由于尾部字段可能在传输过程中被丢弃,服务器不应该生成其认为用户代理 必须接收到的尾部字段。

6.5.2. 处理尾部字段

可以发送“Trailer”头字段(第 6.6.2 节)来指示可能在 尾部部分中发送的字段,从而允许接收方在处理内容之前 为接收这些字段做好准备。例如,如果某个字段名称 指示应在接收内容时计算动态校验和,并在收到 尾部字段值后立即进行检查,这会很有用。

与头字段一样,同名尾部字段按照 接收顺序处理;多个同名尾部字段行具有 与将多个值作为成员列表追加等效的语义。在一条消息中 可能多次生成的尾部字段必须被 定义为基于列表的字段,即使每个成员值在每个收到的 字段行中只处理一次。

在消息末尾,接收方可以将收到的 尾部字段集合视为名称/值对的数据结构,类似于(但 独立于)头字段。其他处理要求(如果有)可以 在预期用于尾部的字段规范中定义。

6.6. 消息元数据

描述消息本身的字段,例如消息在何时以及如何 生成,可以同时出现在请求和响应中。

6.6.1. Date

“Date”头字段表示消息 生成的日期和时间,其语义与 [RFC5322] 第 3.6.1 节中定义的生成日期字段 (orig-date) 相同。字段值是 第 5.6.7 节中定义的 HTTP-date。

示例如下

Date: Tue, 15 Nov 1994 08:12:31 GMT

生成 Date 头字段的发送方应该将 其字段值生成为对消息生成日期和时间的最佳可用近似值 。理论上,该日期应当表示刚要生成 消息内容之前的时刻。实际上,发送方可以在消息生成 期间的任何时刻生成日期值。

具有时钟(定义见 第 5.6.7 节)的源服务器必须 在所有 2xx (成功)、3xx(重定向)和 4xx(客户端错误)响应中生成 Date 头字段,并且可以在 1xx(信息性)和 5xx (服务器错误)响应中生成 Date 头字段。

没有时钟的源服务器不得生成 Date 头字段。

具有时钟的接收方收到没有 Date 头字段的响应消息时 必须记录其接收时间,并且如果消息被缓存或 向下游转发,则向消息的头部部分追加一个相应的 Date 头字段 。

具有时钟的接收方收到 Date 头字段 值无效的响应时,可以将该值替换为收到响应的时间 。

用户代理可以在请求中发送 Date 头字段,尽管 通常不会这样做,除非认为它能向 服务器传达有用信息。例如,如果预期服务器 会根据用户代理和服务器时钟之间的差异调整其对用户请求的解释, HTTP 的自定义应用可以传达 Date。

6.6.2. Trailer

“Trailer”头字段提供发送方预计 在该消息中作为尾部字段发送的字段名称列表。这使接收方可以在开始处理内容之前 为接收所指示的元数据做好准备。

例如,发送方可以指示将在内容 流式传输时计算签名,并将最终签名作为尾部字段提供。这使 接收方能够在接收内容时实时执行相同检查。

打算在消息中生成一个或多个尾部字段的发送方应该在该消息的头部部分中生成 Trailer 头字段,以 指示哪些字段可能出现在尾部中。

如果中间方在传输过程中丢弃尾部部分,Trailer 字段可以提供有关 哪些元数据丢失的提示,尽管不能保证 Trailer 的发送方 最终一定会发送所列出的字段。

7. 路由 HTTP 消息

HTTP 请求消息的路由由每个客户端根据目标资源、 客户端的代理配置以及入站连接的建立或重用来确定。 相应响应的路由沿同一连接链返回客户端。

7.1. 确定目标资源

尽管 HTTP 用于各种各样的应用,但大多数客户端依赖与通用 Web 浏览器相同的资源标识机制和配置技术 。即使通信选项被硬编码在客户端配置中,我们 也可以将它们的组合效果视为一个 URI 引用(第 4.1 节)。

URI 引用会被解析为其绝对形式,以获得目标 URI。目标 URI 排除引用的片段组件(如果存在),因为 片段标识符保留用于客户端处理([URI],第 3.5 节)。

为了对目标资源执行操作,客户端发送一条请求消息, 其中包含已解析目标 URI 的足够多组件,使接收方能够标识 同一资源。由于历史原因,解析后的目标 URI 组件 统称为请求目标,它们在消息 控制数据和 Host 头字段(第 7.2 节)中发送。

有两种不常见的情况,请求目标组件采用 特定于方法的形式:

  • 对于 CONNECT(第 9.3.6 节),请求目标是隧道 目的地的主机名和端口号,两者以冒号分隔。
  • 对于 OPTIONS(第 9.3.7 节),请求目标可以是单个星号 ("*")。

有关详细信息,请参见相应的方法定义。这些形式不得 与其他方法一起使用。

收到客户端请求后,服务器根据其本地配置和传入连接 上下文,从收到的组件重构目标 URI 。这种重构是每个主要协议版本特有的。例如, [HTTP/1.1] 的第 3.3 节定义了 服务器如何确定 HTTP/1.1 请求的目标 URI。

7.2. Host 和 :authority

请求中的“Host”头字段提供来自 目标 URI 的主机和端口信息,使源服务器在处理 多个主机名的请求时能够区分资源。

在 HTTP/2 [HTTP/2] 和 HTTP/3 [HTTP/3] 中,Host 头字段在某些情况下 被请求控制数据中的“:authority”伪头字段取代。

  Host = uri-host [ ":" port ] ; 第 4 节

目标 URI 的 authority 信息对于处理请求至关重要。用户代理 必须在请求中生成 Host 头字段,除非它将 该信息作为“:authority”伪头字段发送。发送 Host 的用户代理 应该将其作为请求头部部分中的第一个字段发送 。

例如,对源服务器上 <http://www.example.org/pub/WWW/> 的 GET 请求将以下列内容开始:

GET /pub/WWW/ HTTP/1.1
Host: www.example.org

由于主机和端口信息充当应用层路由机制,因此它经常 成为试图污染共享缓存或将请求重定向到 非预期服务器的恶意软件的目标。如果拦截代理依赖 主机和端口信息将请求重定向到内部服务器,或者在 共享缓存中将其用作缓存键,而没有先验证被拦截的 连接是否以该主机的有效 IP 地址为目标,则尤其容易受到攻击。

7.3. 路由入站请求

确定目标 URI 及其源之后,客户端决定是否需要网络 请求来实现所需语义,如果需要,则决定该请求 应定向到何处。

7.3.1. 到缓存

如果客户端具有缓存 [CACHING] 并且请求可以由其满足 ,那么请求通常会首先定向到那里。

7.3.2. 到代理

如果请求未由缓存满足,那么典型客户端会检查其 配置,以确定是否要使用代理来满足请求。 代理配置取决于实现,但通常基于 URI 前缀 匹配、选择性 authority 匹配或两者,并且代理本身通常 由“http”或“https”URI 标识。

如果适用“http”或“https”代理,则客户端通过 建立(或重用)与该代理的连接向入站方向连接,然后向其发送一条 HTTP 请求消息,其中包含与客户端目标 URI 匹配的请求目标。

7.3.3. 到源

如果没有适用的代理,典型客户端会调用一个处理程序例程(特定 于目标 URI 的方案)来访问所标识资源。如何 实现这一点取决于目标 URI 方案,并由其相关 规范定义。

第 4.3.2 节定义了如何通过建立(或重用)与 所标识源服务器的入站连接,然后向其发送一条 HTTP 请求消息(其中包含 与客户端目标 URI 匹配的请求目标),来访问“http”资源 。

第 4.3.3 节定义了如何通过建立(或重用)与 对所标识源具有权威性的源服务器之间的入站安全 连接,然后向其发送一条 HTTP 请求消息(其中包含与 客户端目标 URI 匹配的请求目标),来访问“https”资源。

7.4. 拒绝错误定向的请求

一旦服务器收到请求并充分解析到可以确定其目标 URI,服务器便决定是自行处理请求、将请求转发给 另一台服务器、将客户端重定向到不同资源、以错误响应,还是 丢弃连接。此决定可能受到请求或 连接上下文中任何因素的影响,但特别取决于服务器是否已 配置为处理该目标 URI 的请求,以及连接上下文是否 适合该请求。

例如,请求可能被有意或意外地错误定向,使得 收到的 Host 头字段中的信息与连接的主机或端口不同。如果连接来自 受信任网关,则这种不一致可能是预期的;否则,它可能表明有人 试图绕过安全过滤器、诱使服务器提供非公开内容, 或污染缓存。有关消息 路由的安全考虑,请参见 第 17 节。

除非连接来自受信任网关,否则如果目标 URI 的任何特定于方案的要求未满足,源服务器必须拒绝请求。特别是,针对“https”资源的请求必须被拒绝,除非它是通过 使用对该目标 URI 的源有效的证书进行保护的连接接收的,如 第 4.2.2 节所定义。

响应中的 421(错误定向的请求)状态码 表示源服务器已拒绝该请求,因为它似乎 被错误定向(第 15.5.20 节)。

7.5. 响应关联

一个连接可以用于多次请求/响应交换。用于 关联请求和响应消息的机制取决于版本;某些 HTTP 版本使用消息的隐式顺序,而另一些版本使用显式标识符。

所有响应,无论状态码如何(包括临时响应),都可以在收到请求后的任何时间发送 ,即使请求尚未完成。响应可以在其 相应请求完成之前完成(第 6.1 节)。同样,也不 要求客户端等待任何特定时间来获得响应。如果在 合理时间内未收到响应,客户端(包括 中间方)可能放弃请求。

客户端在仍发送相关请求时收到响应,应该继续发送该请求,除非收到 明确的相反指示(例如,参见 [HTTP/1.1] 的第 9.5 节以及 [HTTP/2] 的第 6.4 节)。

7.6. 消息转发

如 第 3.7 节所述, 中间方可以在处理 HTTP 请求和 响应时承担各种角色。某些中间方用于提高性能或可用性,其他 中间方用于访问控制或过滤内容。由于 HTTP 流具有 类似于管道和过滤器架构的特征,因此中间方能够在 流的任一方向上增强(或干扰)的程度没有固有限制 。

即使无法识别协议元素(例如新方法、状态码或字段名称), 也期望中间方转发消息,因为这样可以为 下游接收方保留可扩展性。

不充当隧道的中间方必须实现 Connection 头字段,如 第 7.6.1 节所规定,并排除 仅用于传入连接的字段,不将其转发 。

除非能够防止无限请求循环,否则中间方不得将消息转发给自身 。通常,中间方应当识别 自己的服务器名称,包括任何别名、本地变体或 IP 地址字面量, 并直接响应此类请求。

HTTP 消息可以作为流进行解析,以便增量处理或向 下游转发。但是,发送方和接收方不能依赖 部分消息的增量传递,因为某些实现会出于网络效率、 安全检查或内容转换的目的缓冲或延迟消息转发。

7.6.1. Connection

“Connection”头字段允许发送方列出 当前连接所需的控制选项。

连接选项不区分大小写。

当 Connection 之外的字段用于提供当前连接的控制信息或 有关当前连接的控制信息时,发送方必须在 Connection 头字段中列出相应字段名称。请注意,某些 HTTP 版本禁止为此类信息使用字段,因此不允许 Connection 字段。

中间方在转发消息之前必须解析收到的 Connection 头字段 ,并针对该字段中的每个 connection-option,从 消息中删除名称与该 connection-option 相同的任何头字段或尾部字段, 然后删除 Connection 头字段本身(或将其替换为 中间方自己用于转发消息的控制选项)。

因此,Connection 头字段提供了一种声明式方式,用于区分 仅供直接接收方使用的字段(“逐跳”)与 供链上所有接收方使用的字段(“端到端”),从而使 消息能够自描述,并允许未来针对连接的扩展 得以部署,而无需担心它们会被旧的 中间方盲目转发。

此外,在应用这些字段的语义之后,无论它们是否作为 connection-option 出现,中间方应该删除或替换 已知在转发前需要删除的字段。这包括但 不限于:

发送方不得发送与 供内容所有接收方使用的字段相对应的连接选项。例如,Cache-Control 绝不 适合作为连接选项([CACHING] 的第 5.2 节)。

连接选项并不总是对应消息中存在的字段,因为 如果连接选项没有关联参数,则可能不需要针对连接的字段 。相反,在没有相应连接选项的情况下收到针对连接的字段, 通常表示该字段被中间方错误地 转发,接收方应当忽略它。

定义不对应字段的新连接选项时, 规范作者仍应当保留相应字段名称,以 避免以后发生冲突。此类保留字段名称注册在 “超文本传输协议 (HTTP) 字段名称注册表”中(第 16.3.1 节)。

7.6.2. Max-Forwards

“Max-Forwards”头字段为 TRACE(第 9.3.8 节)和 OPTIONS(第 9.3.7 节) 请求方法提供一种机制,以限制请求被 代理转发的次数。当客户端试图跟踪一个 似乎在链中途失败或循环的请求时,这会很有用。

Max-Forwards 值是一个十进制整数,表示该请求消息 剩余可被转发的次数。

每个收到包含 Max-Forwards 头字段的 TRACE 或 OPTIONS 请求的中间方,在 转发请求之前必须检查并更新其值。如果收到的值为零 (0),中间方不得转发请求;相反,中间方必须作为最终接收方响应。如果收到的 Max-Forwards 值大于零,中间方必须在转发的消息中生成更新后的 Max-Forwards 字段 ,其字段值取以下两者中较小者:a) 收到的值减 一 (1),或 b) 接收方所支持的 Max-Forwards 最大值。

对于使用任何其他请求方法收到的 Max-Forwards 头字段, 接收方可以忽略它。

7.6.3. Via

“Via”头字段指示用户代理和服务器之间(对于请求),或源 服务器和客户端之间(对于响应)存在的中间协议和 接收方,类似于电子邮件中的“Received”头字段 ([RFC5322] 的第 3.6.7 节)。Via 可用于 跟踪消息转发、避免请求循环以及标识请求/响应链上 发送方的协议能力。

Via 字段值中的每个成员表示转发了 消息的代理或网关。每个中间方都会追加其关于消息如何 被接收的信息,因此最终结果按照 转发接收方的顺序排列。

代理在其转发的每条消息中必须发送适当的 Via 头字段,如 下文所述。HTTP 到 HTTP 网关在每个入站 请求消息中必须发送适当的 Via 头字段,并且在转发的 响应消息中可以发送 Via 头字段。

对于每个中间方,received-protocol 指示消息的上游发送方所使用的 协议和协议版本。因此,Via 字段值 记录请求/响应链公开的协议能力,使其 对下游接收方保持可见;这有助于确定 哪些不向后兼容的特性可以安全地用于响应或 后续请求,如 第 2.5 节所述。为简洁起见,当收到的协议是 HTTP 时, 会省略 protocol-name。

received-by 部分通常是随后转发消息的接收方 服务器或客户端的主机和可选端口号。但是,如果真实主机 被认为是敏感信息,发送方可以 用假名替换它。如果未提供端口,接收方可以将其解释为消息是在 received-protocol 的默认 端口(如果有)上收到的。

发送方可以生成注释以标识 每个接收方的软件,类似于 User-Agent 和 Server 头字段。但是,Via 中的注释是可选的,接收方可以在转发消息之前删除它们。

例如,一条请求消息可以从 HTTP/1.0 用户代理发送到一个 内部代理(代号“fred”),该代理使用 HTTP/1.1 将请求转发到 p.example.net 上的公共代理,后者再将请求转发到 www.example.com 上的源服务器以完成请求。那么 www.example.com 收到的请求 将具有以下 Via 头字段:

Via: 1.0 fred, 1.1 p.example.net

用作穿过网络防火墙门户的中间方不应该 转发防火墙区域内主机的名称和端口,除非 明确启用了此功能。如果未启用,此类中间方应该将防火墙后任何主机的每个 received-by 主机 替换为该主机的适当假名。

如果条目具有相同的 received-protocol 值,中间方可以将 Via 头字段列表成员的一个有序子序列组合成单个成员。例如,

Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy

可以折叠为

Via: 1.0 ricky, 1.1 mertz, 1.0 lucy

除非多个列表成员全部处于同一组织控制下且主机已 被替换为假名,否则发送方不应该组合它们。发送方不得组合 received-protocol 值不同的成员。

7.7. 消息转换

某些中间方包含转换消息及其内容的功能。例如,代理 可以在图像格式之间转换,以节省缓存空间或 减少慢速链路上的流量。但是,当这些转换应用于 面向关键应用的内容时,可能会出现运行问题, 例如医学成像或科学数据分析,尤其是在使用完整性检查 或数字签名来确保收到的内容与 原始内容完全相同时。

如果 HTTP 到 HTTP 代理被设计或 配置为以语义上有意义的方式修改消息(即超出正常 HTTP 处理所需修改之外, 以一种对原始发送方而言重要或 对下游接收方可能重要的方式更改消息),则称为转换代理 。例如,转换代理可以充当共享注释 服务器(修改响应以包含对本地注释数据库的引用)、 恶意软件过滤器、格式转码器或隐私过滤器。此类转换 被认为是选择该代理的客户端(或客户端组织)所期望的。

如果代理收到的目标 URI 中的主机名不是完全限定域 名,则在转发请求时,它可以将自己的域添加到收到的主机名中 。如果目标 URI 包含完全限定域名, 代理不得更改主机名。

代理在将收到的目标 URI 转发到下一个入站服务器时,除非转发 协议要求,否则不得修改其中的“absolute-path”和“query”部分 。例如,通过 HTTP/1.1 将请求转发到源 服务器的代理,会将空路径替换为“/”([HTTP/1.1] 的第 3.2.1 节) 或“*”([HTTP/1.1] 的第 3.2.4 节), 具体取决于请求方法。

代理不得转换包含 no-transform 缓存指令的响应消息内容(第 6.4 节)( [CACHING] 的第 5.2.2.6 节)。请注意, 这不适用于不更改内容的消息转换,例如 添加或删除传输编码([HTTP/1.1] 的第 7 节)。

代理可以转换不包含 no-transform 缓存指令的消息内容。转换 200 (OK) 响应内容的代理可以通过将响应状态码 更改为 203(非权威信息)(第 15.3.4 节)来告知下游 接收方已经应用了转换。

除非字段定义明确允许此类修改,或 出于隐私或安全考虑认为有必要修改,否则代理不应该修改提供 通信链端点、资源状态或选定表示(内容除外)相关信息的头字段。

7.8. Upgrade

“Upgrade”头字段旨在提供一种简单机制,用于 在同一连接上从 HTTP/1.1 转换到其他协议。

客户端可以在请求的 Upgrade 头 字段中发送协议名称列表,以邀请服务器在发送最终响应之前 切换到一个或多个所列协议,顺序按优先级递减。服务器可以忽略收到的 Upgrade 头字段,如果它希望 在该连接上继续使用当前协议。Upgrade 不能用于强制 更改协议。

尽管协议名称注册时具有首选大小写形式,但接收方应该在将每个 protocol-name 与支持的协议匹配时使用不区分大小写的比较。

发送 101(切换协议) 响应的服务器必须发送 Upgrade 头字段,以指示连接 正在切换到的新协议;如果正在切换多个协议层, 发送方必须按层级递增顺序列出协议 。服务器不得切换到 客户端未在相应请求的 Upgrade 头 字段中指示的协议。服务器可以选择忽略客户端指示的优先级顺序 ,并根据其他因素选择新协议,例如 请求的性质或服务器当前负载。

发送 426(需要升级) 响应的服务器必须发送 Upgrade 头字段,以按 优先级递减顺序指示可接受的协议。

服务器可以在任何其他响应中发送 Upgrade 头字段,以 宣告它支持升级到所列协议,并在适用于 未来请求时按优先级递减顺序列出。

以下是客户端发送的一个假设示例:

GET /hello HTTP/1.1
Host: www.example.com
Connection: upgrade
Upgrade: websocket, IRC/6.9, RTA/x11

协议更改后应用层通信的能力和性质 完全取决于所选择的新协议。但是,在 发送 101(切换协议)响应后,服务器应立即 继续响应原始请求,就像它已 在新协议中收到等效请求一样(即,协议更改后服务器仍有一个 尚未满足的请求,并且应当 在无需重复请求的情况下满足该请求)。

例如,如果在 GET 请求中收到 Upgrade 头字段并且服务器 决定切换协议,则它首先以 HTTP/1.1 中的 101(切换协议)消息响应,然后立即 使用新协议中相当于对目标 资源执行 GET 的响应。这使连接能够升级到与 HTTP 具有相同语义的协议,而无需 额外往返所带来的延迟。除非新协议能够遵循收到的消息语义, 否则服务器不得切换协议;OPTIONS 请求可以由任何协议处理 。

以下是对上述假设请求的示例响应:

HTTP/1.1 101 Switching Protocols
Connection: upgrade
Upgrade: websocket

[... 数据流切换到 websocket,并对
(由新协议定义的)"GET /hello" 请求作出适当响应 ...]

Upgrade 的发送方必须同时在 Connection 头字段(第 7.6.1 节)中发送“Upgrade”连接选项,以通知中间方不要转发该字段。服务器 在 HTTP/1.0 请求中收到 Upgrade 头字段时必须 忽略该 Upgrade 字段。

客户端在完全发送完请求消息之前,不能在连接上开始使用升级后的协议 (即客户端不能在 发送消息的中途更改协议)。如果服务器同时收到 Upgrade 和 Expect 头字段,且后者带有“100-continue” 期望(第 10.1.1 节),则服务器在发送 101(切换协议)响应之前必须先发送 100(继续)响应。

Upgrade 头字段仅适用于在现有 连接之上切换协议;它不能用于切换底层连接(传输)协议, 也不能将现有通信切换到不同连接。对于这些用途, 更适合使用 3xx(重定向) 响应(第 15.4 节)。

本规范仅定义协议名称“HTTP”供 超文本传输协议族使用,如 第 2.5 节的 HTTP 版本规则以及 本规范未来更新所定义。其他协议名称应当使用 第 16.7 节中定义的注册过程进行注册。

8. 表示数据和元数据

8.1. 表示数据

与 HTTP 消息关联的表示数据要么作为消息的内容 提供,要么由消息语义和目标 URI 引用。 表示数据采用由表示元数据 头字段定义的格式和编码。

表示数据的数据类型通过头字段 Content-Type 和 Content-Encoding 确定。它们定义了一个 两层、有序的编码模型:

  representation-data := Content-Encoding( Content-Type( data ) )

8.2. 表示元数据

表示头字段提供有关表示的元数据。当消息 包含内容时,表示头字段描述如何解释该数据。 在对 HEAD 请求的响应中,表示头字段描述 如果同一请求是 GET 时本应包含在内容中的表示数据。

8.3. Content-Type

"Content-Type" 头字段指示相关 表示的媒体类型:要么是消息内容中包含的表示,要么是由消息语义 确定的选定表示。所指示的媒体类型同时定义数据 格式以及在接收到的消息语义范围内、对 Content-Encoding 指示的任何内容编码进行解码后,接收方应如何处理该数据。

媒体类型定义于 第 8.3.1 节。该 字段的一个示例是

Content-Type: text/html; charset=ISO-8859-4

生成包含内容的消息的发送方应该 在该消息中生成 Content-Type 头字段,除非发送方不知道 所包含表示预期的媒体类型。如果不存在 Content-Type 头字段, 接收方可以假定媒体类型为 "application/octet-stream" ([RFC2046], 第 4.5.1 节) 或检查数据以确定其类型。

实际上,资源所有者并不总能正确配置其源服务器,以便 为给定表示提供正确的 Content-Type。某些用户代理检查 内容,并在某些情况下覆盖收到的类型 (例如,参见 [Sniffing])。这种 "MIME 嗅探" 存在对 数据得出错误结论的风险,这可能使用户面临额外的安全 风险 (例如,"权限提升")。此外,不同媒体类型通常共享一种 通用数据格式,仅在数据预期如何处理方面有所不同,而这 无法仅通过检查数据来区分。实现嗅探时, 鼓励实现者提供一种让用户禁用它的方法。

尽管 Content-Type 被定义为单值字段,但有时会错误地 多次生成,从而产生看起来像列表的组合字段值。 接收方通常尝试通过使用列表中最后一个语法有效的 成员来处理此错误;如果不同实现具有不同的错误处理行为, 这可能导致互操作性和安全问题。

8.3.1. 媒体类型

HTTP 在 Content-Type (第 8.3 节) 和 Accept (第 12.5.1 节) 头字段中使用媒体类型 [RFC2046] ,以提供开放且 可扩展的数据类型化和类型协商。媒体类型同时定义数据格式 和各种处理模型:如何根据 消息上下文处理该数据。

type 和 subtype 令牌不区分大小写。

type/subtype 后面可以跟以分号分隔的 参数 (第 5.6.6 节),形式为 名称/值对。参数是否存在对于 媒体类型的处理可能很重要,具体取决于媒体类型 注册表中的定义。参数值可能区分大小写,也可能不区分,具体取决于 参数名称的语义。

例如,以下媒体类型在描述使用 UTF-8 字符编码方案 编码的 HTML 文本数据方面是等价的,但为了 一致性首选第一个 ("charset" 参数值在 [RFC2046], 第 4.1.2 节中定义为不区分大小写):

  text/html;charset=utf-8
  Text/HTML;Charset="utf-8"
  text/html; charset="utf-8"
  text/html;charset=UTF-8

媒体类型应当根据 [BCP13] 中定义的程序向 IANA 注册。

8.3.2. 字符集

HTTP 使用字符集名称来指示或协商文本表示的字符编码 方案 ([RFC6365], 第 2 节)。 在本文定义的字段中,charset 名称要么出现在参数中 (Content-Type), 要么对于 Accept-Encoding,以普通 token 的形式出现。在这两种 情况下,charset 名称都以不区分大小写的方式匹配。

Charset 名称应当按照 第 2 节中 [RFC2978] 定义的程序注册到 IANA "Character Sets" 注册表 (https://www.iana.org/assignments/character-sets) 中。

8.3.3. 多部分类型

MIME 提供了若干 "multipart" 类型——在单个消息主体中封装一个或多个 表示。所有 multipart 类型共享一种通用 语法,如 第 5.1.1 节中 [RFC2046] 所定义, 并将 boundary 参数作为媒体类型值的一部分。消息主体 本身就是一个协议元素;发送方必须仅生成 CRLF 来表示主体部分之间的换行。

HTTP 消息分帧不使用 multipart 边界作为消息 主体长度的指示符,不过生成或处理 内容的实现可能会使用它。例如,"multipart/form-data" 类型通常用于在请求中携带表单 数据,如 [RFC7578] 所述, 而 "multipart/byteranges" 类型由本规范定义,用于某些 206 (部分内容) 响应 (参见 第 15.3.7 节)。

8.4. Content-Encoding

"Content-Encoding" 头字段指示除了媒体类型固有编码之外, 哪些内容编码已应用于表示,因此也指示为了获得 Content-Type 头字段所引用媒体类型的数据, 必须应用哪些解码 机制。Content-Encoding 主要用于允许压缩表示的数据 而不丢失其底层媒体类型的身份。

其使用示例是

Content-Encoding: gzip

如果对表示应用了一个或多个编码,则应用这些 编码的发送方必须生成 Content-Encoding 头字段, 按应用顺序列出内容编码。请注意,名为 "identity" 的编码为其在 Accept-Encoding 中的特殊角色保留,因此不应该 包含它。

有关编码参数的附加信息可以由本规范未定义的其他头 字段提供。

与 Transfer-Encoding (第 6.1 节,见 [HTTP/1.1]) 不同,Content-Encoding 中列出的编码是表示的特征;表示 根据编码后的形式定义,除非元数据 定义另有说明,否则关于表示的所有其他元数据都是关于编码后的形式。 通常,仅在渲染或 类似用途之前才对表示进行解码。

如果媒体类型包含固有编码,例如始终 压缩的数据格式,那么即使该编码碰巧与某种内容编码使用相同的算法, 也不会在 Content-Encoding 中再次声明该编码。只有在由于某种奇怪原因, 再次应用该内容编码以形成 表示时,才会列出该内容编码。同样,源服务器可以选择将同一数据发布为 多个表示,这些表示仅在编码是定义为 Content-Type 的一部分还是 Content-Encoding 方面有所不同,因为 某些用户代理在处理每个响应时会有不同的行为 (例如,打开 "另存为 ..." 对话框,而不是自动解压并渲染内容)。

如果请求消息中的表示使用了不可接受的内容编码,源服务器可以以 415 (不支持的媒体类型) 状态码响应。

8.4.1. 内容编码

内容编码值指示已经或可以 应用于表示的编码转换。内容编码主要用于允许 压缩表示或以其他有用方式转换表示,而不丢失其 底层媒体类型的身份,也不丢失信息。通常, 表示以编码形式存储、直接传输,并且仅由 最终接收方解码。

所有内容编码都不区分大小写,并且应当注册到 "HTTP 内容编码注册表" 中,如 第 16.6 节所述

Content-coding 值用于 Accept-Encoding (第 12.5.3 节) 和 Content-Encoding (第 8.4 节) 头字段。

8.4.1.1. Compress 编码

"compress" 编码是一种自适应 Lempel-Ziv-Welch (LZW) 编码 [Welch] ,通常由 UNIX 文件压缩程序 "compress" 生成。接收方 应该将 "x-compress" 视为与 "compress" 等价。

8.4.1.2. Deflate 编码

"deflate" 编码是一种 "zlib" 数据格式 [RFC1950] ,其中包含一个使用 Lempel-Ziv (LZ77) 压缩算法与 Huffman 编码组合的 "deflate" 压缩数据流 [RFC1951] 。

8.4.1.3. Gzip 编码

"gzip" 编码是一种带 32 位循环冗余校验 (CRC) 的 LZ77 编码, 通常由 gzip 文件压缩程序生成 [RFC1952]。 接收方应该将 "x-gzip" 视为与 "gzip" 等价。

8.5. Content-Language

"Content-Language" 头字段描述表示预期 受众的自然语言。请注意,这可能不等同于 表示中使用的所有语言。

语言标签定义于 第 8.5.1 节。Content-Language 的主要用途是允许用户根据自己的首选语言 标识和区分表示。因此, 如果内容仅面向能够读懂丹麦语的受众,则适当的字段是

Content-Language: da

如果未指定 Content-Language,则默认内容面向所有 语言受众。这可能意味着发送方不认为它特定于 任何自然语言,或者发送方不知道它面向哪种语言。

对于面向多个受众的内容,可以列出多种语言 。例如,以原始毛利语和英语版本 同时呈现的 "怀唐伊条约" 将需要

Content-Language: mi, en

但是,仅仅因为表示中存在多种语言,并不 意味着它面向多种语言的受众。一个例子是 初学者语言教材,例如 "拉丁语第一课",它显然面向 能够读懂英语的受众。在这种情况下,Content-Language 正确地只应包含 "en"。

Content-Language可以应用于任何媒体类型——它并不 仅限于文本文档。

8.5.1. 语言标签

语言标签,如 [RFC5646]中所定义,用于标识 人类为了向其他人类 传达信息而口头、书面或以其他方式表达的自然语言。明确 排除计算机语言。

HTTP 在 Accept-Language 和 Content-Language 头字段中使用语言标签。Accept-Language 使用 第 12.5.4 节中定义的更宽泛的 language-range 产生式,而 Content-Language 使用下面定义的 language-tag 产生式 。

  language-tag = <Language-Tag, see [RFC5646], Section 2.1>

语言标签是一个或多个不区分大小写的子标签组成的序列,每个子标签 由连字符 ("-", %x2D) 分隔。在大多数情况下,语言标签由 标识一大类相关语言的主语言子标签组成 (例如, "en" = 英语),之后可选地跟随一系列细化或 缩小该语言范围的子标签 (例如,"en-CA" = 加拿大使用的英语 变体)。语言标签中不允许空白。示例标签包括:

  fr, en-US, es-419, az-Arab, x-pig-latin, man-Nkoo-GN

有关更多 信息,请参见 [RFC5646]。

8.6. Content-Length

"Content-Length" 头字段以十进制非负整数八位字节数的形式指示相关表示的数据长度 。当将表示 作为内容传输时,Content-Length 特指所包含的数据量,因此它 可用于界定分帧 (例如,第 6.2 节,见 [HTTP/1.1])。在其他 情况下,Content-Length 指示选定表示的当前长度,可由 接收方用于估算传输时间或与之前存储的 表示进行比较。

示例如下

Content-Length: 3495

当方法为所包含内容定义了含义并且未发送 Transfer-Encoding 时,用户代理应该在请求中发送 Content-Length。例如, 用户代理通常会在 POST 请求中发送 Content-Length,即使 值为 0 (表示空内容)。当请求消息不包含内容且 方法语义不预期此类数据时,用户代理不应该 发送 Content-Length 头字段。

服务器可以在对 HEAD 请求的响应中发送 Content-Length 头字段 (第 9.3.2 节);除非其 字段值等于同一请求使用 GET 方法时响应内容中 本应发送的八位字节十进制数量,否则服务器不得在此类响应中发送 Content-Length 。

服务器可以在对条件 GET 请求的 304 (未修改) 响应中发送 Content-Length 头字段 (第 15.4.5 节);除非其字段值等于 对同一请求的 200 (OK) 响应内容中本应发送的八位字节十进制数量,否则服务器不得 发送 Content-Length。

服务器在任何状态码为 1xx (信息性) 或 204 (无内容) 的响应中不得发送 Content-Length 头字段。服务器 在对 CONNECT 请求的任何 2xx (成功) 响应中不得发送 Content-Length 头字段 (第 9.3.6 节)。

除上述定义的情况外,在没有 Transfer-Encoding 的情况下,当在完整头部部分发送之前 已知内容大小时,源服务器 应该发送 Content-Length 头字段。这将允许下游 接收方测量传输进度、知道收到的消息何时完整,并 可能复用连接来处理其他请求。

任何大于或等于零的 Content-Length 字段值都是有效的。由于 内容长度没有预定义限制,接收方必须 预期可能出现很大的十进制数字,并防止整数 转换溢出导致解析错误,或整数转换导致精度损失 (第 17.5 节)。

由于 Content-Length 在 HTTP/1.1 中用于消息定界,其字段值 可能影响下游接收方解析消息的方式,即使直接 连接未使用 HTTP/1.1。如果消息由下游 中间方转发,则与收到的 消息分帧不一致的 Content-Length 字段值可能会因请求走私或响应 拆分而导致安全故障。

因此,发送方不得转发具有已知 不正确 Content-Length 头字段值的消息。

同样,发送方不得转发 Content-Length 头字段值与上述 ABNF 不匹配的消息,但有一个 例外:如果 Content-Length 头字段值由相同的 十进制值作为逗号分隔列表重复组成 (例如,"Content-Length: 42, 42"),接收方可以将消息作为无效消息拒绝,或者将该无效 字段值替换为该十进制值的单个实例,因为这很可能表明 上游消息处理器生成或组合了重复值。

8.7. Content-Location

"Content-Location" 头字段引用一个 URI,该 URI 可用作 与此消息内容中表示相对应的特定资源的标识符。 换言之,如果在此 消息生成时对该 URI 执行 GET 请求,那么 200 (OK) 响应 将包含与此消息内容中所包含表示相同的表示。

字段值要么是 absolute-URI,要么是 partial-URI。在后一种情况下 (第 4 节),所引用的 URI 相对于目标 URI ([URI], 第 5 节)。

Content-Location 值不能替代目标 URI (第 7.1 节)。它 是表示元数据。它与 第 4 节中 [RFC2557] 为 MIME 主体部分定义的同名头字段具有相同的语法和语义。 但是,它出现在 HTTP 消息中会对 HTTP 接收方产生一些特殊影响。

如果 Content-Location 包含在 2xx (成功) 响应消息中,并且其值 (转换为绝对 形式后) 引用与目标 URI 相同的 URI,那么接收方可以认为该内容是在消息生成日期所指示时间该 资源的当前表示。对于 GET (第 9.3.1 节) 或 HEAD (第 9.3.2 节) 请求,这与 服务器未提供 Content-Location 时的默认语义相同。 对于像 PUT (第 9.3.4 节) 或 POST (第 9.3.3 节) 这样的状态更改请求,它意味着服务器响应包含 该资源的新表示,从而将其与 可能仅报告操作情况的表示区分开来 (例如,"成功了!")。这允许创作 应用程序更新其本地副本,而无需后续 GET 请求。

如果 Content-Location 包含在 2xx (成功) 响应消息中,并且其字段值引用与目标 URI 不同的 URI,那么源服务器声明该 URI 是与所包含表示相对应的 不同资源的标识符。只有当两个标识符共享同一资源所有者时, 才能信任这种声明,而这无法 通过 HTTP 以编程方式确定。

  • 对于 GET 或 HEAD 请求的响应,这表示目标 URI 引用受内容协商影响的资源,并且 Content-Location 字段值是选定表示更具体的标识符。
  • 对于状态更改方法的 201 (已创建) 响应, 与 Location 字段值相同的 Content-Location 字段值表示此 内容是新创建资源的当前表示。
  • 否则,此类 Content-Location 表示该内容是 报告所请求操作状态的表示,并且可以在给定 URI 获取同一报告 (供以后使用 GET 访问)。例如,通过 POST 请求 执行的购买交易可能在 200 (OK) 响应内容中包含收据文档;Content-Location 字段值提供一个标识符,用于在 将来检索同一收据的副本。

在请求消息中发送 Content-Location 的用户代理表示,其值 引用该用户代理最初获取所包含 表示内容的位置 (在该用户代理进行任何修改之前)。换言之, 用户代理正在提供指向原始表示来源的反向链接。

在请求消息中收到 Content-Location 字段的源服务器必须将该信息视为临时请求上下文,而不是 要逐字保存为表示一部分的元数据。源服务器 可以使用该上下文指导请求处理,或将其 保存用于其他用途,例如用于源链接或版本控制元数据。但是, 源服务器不得使用此类上下文信息改变 请求语义。

例如,如果客户端对协商资源发出 PUT 请求,并且源 服务器接受该 PUT (不重定向),则该资源的新状态 预期与该 PUT 中提供的一个表示一致; Content-Location 不能用作反向内容选择标识符的形式来 仅更新协商表示中的一个。如果用户代理希望获得 后一种语义,它会直接将 PUT 应用于 Content-Location URI。

8.8. 验证器字段

如果资源元数据可以在前置条件 (第 13.1 节) 中用于发出 条件请求 (第 13 节),则称其为验证器。验证器字段传达选定 表示 (第 3.2 节) 的当前验证器。

在对安全请求的响应中,验证器字段描述源服务器 在处理响应时选择的选定表示。请注意,根据 方法和状态码语义,给定响应的选定表示 不一定与作为响应内容包含的表示相同。

在对状态更改请求的成功响应中,验证器字段描述 因处理请求而替换了先前选定表示的新表示。

例如,201 (已创建) 响应中的 ETag 字段传达新创建资源表示的实体标签,因此 该实体标签可以在以后的条件请求中用作验证器,以防止 "更新丢失" 问题。

本规范定义了两种常用于观察 资源状态和测试前置条件的元数据形式:修改日期 (第 8.8.2 节) 和不透明实体标签 (第 8.8.3 节)。 反映资源状态的其他元数据已由 HTTP 的各种扩展 定义,例如 Web 分布式创作和版本控制 [WEBDAV], 这些超出了本规范的范围。

8.8.1. 弱与强

验证器有两种:强验证器或弱验证器。弱验证器易于生成, 但对比较的用途要小得多。强验证器非常适合比较, 但高效生成可能非常困难 (有时甚至不可能)。 HTTP 并不要求所有形式的资源都遵循相同强度的 验证器,而是公开正在使用的验证器类型,并对 何时可以将弱验证器用作前置条件施加限制。

强验证器是一种表示元数据,每当 表示数据发生变化,并且这种变化可以在对 GET 的 200 (OK) 响应内容中观察到时, 它的值就会改变。

强验证器也可能因表示 数据变化以外的原因而改变,例如表示元数据中具有语义意义的部分 发生变化时 (例如,Content-Type),但 仅在有必要使远程缓存和创作 工具保存的响应失效时才更改该值,最符合源服务器的利益。

缓存条目可能持续任意长的时间,而不受过期 时间影响。因此,缓存可能尝试使用很久以前 获得的验证器验证条目。强验证器在特定资源 随时间关联的所有表示的所有版本中都是唯一的。但是,这 并不意味着它在不同资源的表示之间也是唯一的 (即, 同一个强验证器可能同时用于多个资源的表示 ,并不意味着这些表示等价)。

实际中使用着多种强验证器。最佳验证器基于 严格的修订控制,其中表示的每次更改都会 在该表示可通过 GET 访问之前分配唯一的节点名称和修订标识符 。如果表示数据在 响应头字段发送之前可用,并且无需 每次收到验证请求时重新计算摘要,那么应用于表示数据的抗碰撞哈希函数也足够。但是,如果资源具有 仅在元数据上不同的不同 表示,例如可能发生在恰好共享同一数据格式的媒体类型之间的内容 协商中,则源服务器需要在验证器中加入附加信息,以 区分这些表示。

相比之下,弱验证器是一种表示元数据,它可能不会 随表示数据的每次变化而改变。这种弱性可能源于 值计算方式的限制 (例如,时钟分辨率)、无法 确保资源所有可能表示的唯一性,或者资源 所有者希望根据自行确定的 等价关系集合而不是唯一数据序列来对表示进行分组。

每当源服务器 认为先前的表示不能作为当前 表示的可接受替代时,它应该更改弱实体标签。换言之,每当 源服务器希望缓存使旧响应失效时,弱实体标签都应当更改。

例如,根据动态测量、内容每 秒都发生变化的天气报告表示,可以被分组为具有相同弱验证器的一组等价 表示 (从源服务器的角度来看) ,以允许缓存表示在合理时间内有效 (可能根据服务器负载或天气质量动态调整)。同样,如果 表示的修改时间仅定义为一秒分辨率, 那么如果表示可能在一秒内被修改 两次并在这些修改之间被检索,它可能是弱验证器。

同样,如果一个验证器同时由给定资源的两个或更多表示共享, 除非这些表示具有相同的 表示数据,否则该验证器就是弱的。例如,如果源服务器为 应用了 gzip 内容编码的表示发送与未使用内容编码的表示相同的验证器 ,那么该验证器就是弱的。但是,如果两个同时存在的 表示仅在表示元数据上不同,例如当同一表示数据 可使用两种不同媒体类型时,它们可以共享同一个强验证器。

强验证器可用于所有条件请求,包括缓存 验证、部分内容范围和避免 "更新丢失"。弱验证器 仅可用于客户端不需要与先前获得的 表示数据完全相等的情况,例如验证缓存条目或将 Web 遍历限制为近期更改。

8.8.2. Last-Modified

响应中的 "Last-Modified" 头字段提供一个时间戳,指示 源服务器认为选定表示最后 修改的日期和时间,该时间在处理请求结束时确定。

其使用示例是

Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
8.8.2.1. 生成

对于能够合理且一致地 确定最后修改日期的任何选定表示,源服务器应该发送 Last-Modified,因为它在条件请求和评估 缓存新鲜度 ([CACHING]) 中的使用可以显著减少 不必要的传输,并显著提高服务可用性和 可扩展性。

表示通常是资源 接口背后许多部分的总和。最后修改时间通常是这些 部分中任何一个最近一次发生变化的时间。如何为任何给定资源确定该值 是超出本规范范围的实现细节。

源服务器应该尽可能在接近它为响应生成 Date 字段值的时间获取表示的 Last-Modified 值。这 允许接收方准确评估表示的 修改时间,特别是在表示接近 响应生成时间发生变化时。

具有时钟 (如 第 5.6.7 节中所定义) 的源服务器不得 生成晚于服务器消息 生成时间的 Last-Modified 日期 (Date, 第 6.6.1 节)。如果最后 修改时间来自实现特定的元数据,而根据源服务器的时钟, 其求值结果是未来某个时间, 那么源服务器必须将该值替换为 消息生成日期。这可以防止未来的修改日期对 缓存验证产生不利影响。

没有时钟的源服务器不得为响应生成 Last-Modified 日期,除非该日期值由 其他系统 (大概是有时钟的系统) 分配给该资源。

8.8.2.2. 比较

Last-Modified 时间在请求中用作验证器时隐式为弱验证器, 除非可以使用以下规则推断它是强验证器:

  • 验证器正由源服务器与表示的实际当前 验证器进行比较,并且
  • 该源服务器可靠地知道相关表示在所提供验证器所覆盖的一秒内没有 改变两次;

或者

  • 验证器即将由客户端在 If-Modified-Since、If-Unmodified-Since 或 If-Range 头字段中使用,因为 客户端具有相关表示的缓存条目,并且
  • 该缓存条目包含一个 Date 值,该值至少比 Last-Modified 值晚一秒,并且 客户端有理由认为它们由同一个时钟生成,或者 Last-Modified 和 Date 值之间存在足够大的差异,使 时钟同步问题不太可能;

或者

  • 验证器正由中间缓存与 其为表示保存的缓存条目中的验证器进行比较,并且
  • 该缓存条目包含一个 Date 值,该值至少比 Last-Modified 值晚一秒,并且 缓存有理由认为它们由同一个时钟生成,或者 Last-Modified 和 Date 值之间存在足够大的差异,使 时钟同步问题不太可能。

这种方法依赖于以下事实:如果两个不同响应由 源服务器在同一秒内发送,但两者具有相同的 Last-Modified 时间, 那么这些响应中至少一个会有一个与其 Last-Modified 时间相等的 Date 值。

8.8.3. ETag

响应中的 "ETag" 字段提供选定表示的当前实体标签,该标签在 处理请求结束时确定。实体标签是一个不透明 验证器,用于区分同一资源的多个表示, 无论这些多个表示是由于资源状态 随时间变化、内容协商导致多个表示同时 有效,还是两者兼有。实体标签由不透明的带引号字符串组成, 前面可能带有弱性指示符。

  ETag       = entity-tag

  entity-tag = [ weak ] opaque-tag
  weak       = %s"W/"
  opaque-tag = DQUOTE *etagc DQUOTE
  etagc      = %x21 / %x23-7E / obs-text
             ; 除双引号外的 VCHAR,加上 obs-text

在不便存储修改日期、 HTTP-date 值的一秒分辨率不足,或者修改 日期未得到一致维护的情况下,实体标签可比修改日期提供更可靠的验证。

示例:

ETag: "xyzzy"
ETag: W/"xyzzy"
ETag: ""

实体标签可以是弱验证器,也可以是强验证器,默认为强验证器 。如果源服务器为表示提供实体标签,而该实体标签的 生成不满足强验证器的所有特征 (第 8.8.1 节),那么源服务器必须通过在其不透明 值前加 "W/" (区分大小写) 来将实体标签标记为弱。

发送方可以在尾部部分中发送 ETag 字段 (参见 第 6.5 节)。但是,由于 尾部字段常被忽略,除非实体标签是在发送内容时生成的, 否则最好将 ETag 作为头字段发送。

8.8.3.1. 生成

实体标签背后的原则是,只有服务作者足够了解 资源的实现,能够为该资源选择最准确、 高效的验证机制,并且任何此类机制 都可以映射为简单的八位字节序列以便比较。由于该 值是不透明的,因此客户端无需了解每个实体 标签是如何构造的。

例如,对所有更改应用了实现特定版本控制的资源 可以使用内部修订号,或许再结合 内容协商的变化标识符,以准确区分 表示。其他实现可能使用表示内容的抗碰撞哈希、 各种文件属性的组合,或者具有亚秒 分辨率的修改时间戳。

对于能够合理且一致地确定变化的任何选定 表示,源服务器应该发送 ETag,因为实体标签在条件请求和评估 缓存新鲜度 ([CACHING]) 中的使用可以显著减少 不必要的传输,并显著提高服务可用性、 可扩展性和可靠性。

8.8.3.2. 比较

根据比较上下文是否允许使用弱验证器, 有两种实体标签比较函数:

强比较:
如果两个实体标签都不是弱的,并且它们的 opaque-tag 逐字符匹配,则二者等价。
弱比较:
如果两个实体标签的 opaque-tag 逐字符匹配,则二者等价,无论其中一个或两个是否被标记为 "weak"。

下面的示例展示了一组实体标签对以及 弱比较和强比较函数的结果:

表 3
ETag 1 ETag 2 强比较 弱比较
W/"1" W/"1" 不匹配 匹配
W/"1" W/"2" 不匹配 不匹配
W/"1" "1" 不匹配 匹配
"1" "1" 匹配 匹配
8.8.3.3. 示例:实体标签随 内容协商资源而变化

考虑一个受内容协商影响的资源 (第 12 节),并且 对 GET 请求发送的表示根据 Accept-Encoding 请求 头字段而变化 (第 12.5.3 节):

>> 请求:

GET /index HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip

在这种情况下,响应可能使用 gzip 内容编码,也可能不使用。如果 不使用,响应可能如下:

>> 响应:

HTTP/1.1 200 OK
Date: Fri, 26 Mar 2010 00:05:00 GMT
ETag: "123-a"
Content-Length: 70
Vary: Accept-Encoding
Content-Type: text/plain

你好,世界!
你好,世界!
你好,世界!
你好,世界!
你好,世界!

使用 gzip 内容编码的替代表示如下:

>> 响应:

HTTP/1.1 200 OK
Date: Fri, 26 Mar 2010 00:05:00 GMT
ETag: "123-b"
Content-Length: 43
Vary: Accept-Encoding
Content-Type: text/plain
Content-Encoding: gzip

...二进制数据...

9. 方法

9.1. 概述

请求方法令牌是请求语义的主要来源;它指示 客户端发出此请求的目的,以及客户端期望 什么样的成功结果。

如果请求中存在某些头字段,并且这些附加语义不与 方法冲突,则请求方法的语义可以通过这些头字段的语义进一步专门化 。例如,客户端可以发送条件请求头字段 (第 13.1 节),使所请求的 操作取决于目标资源的当前状态。

HTTP 被设计为可用作分布式对象系统的接口。请求 方法调用要应用于目标资源的操作,其方式与远程方法 调用发送给已标识对象非常类似。

方法令牌区分大小写,因为它可能被用作通往具有区分大小写方法名称的基于对象 系统的网关。按照约定,标准化方法 使用全部大写的 US-ASCII 字母定义。

与分布式对象不同,HTTP 中的标准化请求方法并非 特定于资源,因为统一接口在 基于网络的系统中提供更好的可见性和复用性 [REST]。 标准化方法一旦定义,在应用于任何 资源时都应具有相同的语义,不过每个资源自行决定是否 实现或允许这些语义。

本规范定义了许多 HTTP 中常用的标准化方法, 如下表所示。

表 4
方法名称 说明 章节
GET 传输目标资源的当前表示。 9.3.1
HEAD 与 GET 相同,但不传输响应内容。 9.3.2
POST 对请求 内容执行特定于资源的处理。 9.3.3
PUT 使用请求内容替换目标资源的所有当前表示 。 9.3.4
DELETE 移除目标资源的所有当前表示。 9.3.5
CONNECT 建立到目标 资源所标识服务器的隧道。 9.3.6
OPTIONS 描述目标 资源的通信选项。 9.3.7
TRACE 沿通往 目标资源的路径执行消息环回测试。 9.3.8

所有通用服务器都必须支持 GET 和 HEAD 方法。 所有其他方法都是可选的。

目标资源允许的方法集合可以列在 Allow 头字段中 (第 10.2.1 节)。但是, 允许的方法集合可以动态变化。源服务器收到 无法识别或未实现的请求方法时应该以 501 (未实现) 状态码响应。源 服务器收到能够识别和实现、但不允许用于目标资源的请求方法时, 应该以 405 (方法不允许) 状态码响应。

本规范范围之外的其他方法也已被规定用于 HTTP。所有此类方法都应当注册在 "超文本传输协议 (HTTP) 方法注册表" 中,如 第 16.1 节所述。

9.2. 通用方法属性

9.2.1. 安全方法

如果请求方法定义的语义本质上是只读的,则认为它们是安全的 ;即,客户端不会请求,也不期望在对目标 资源应用安全方法后源服务器发生任何状态变化。同样,合理使用安全方法预计不会对 源服务器造成任何损害、财产损失或异常负担。

安全方法的这一定义并不阻止实现在调用安全方法时包含 可能有害、并非完全只读或会产生 副作用的行为。但是,重要的是, 客户端并未请求这种附加行为,因此不能要求客户端对此负责 。例如,大多数服务器会在 每个响应完成时将请求信息追加到访问日志文件中,而不论方法如何,这仍被视为安全的 ,即使日志存储可能被写满并导致服务器故障。 同样,通过在 Web 上选择广告发起的安全请求通常 会产生向广告账户收费的副作用。

在本规范定义的请求方法中,GET、HEAD、OPTIONS 和 TRACE 方法被定义为安全的。

区分安全和不安全方法的目的是允许自动 检索过程 (蜘蛛程序) 和缓存性能优化 (预取) 在不必担心造成损害的情况下工作。此外,它还允许用户代理在处理 可能不受信任的内容时,对不安全方法的自动使用施加 适当限制。

用户代理在向用户呈现潜在操作时应该区分安全与不安全 方法,以便让用户在请求不安全操作之前 意识到这一点。

当资源的构造方式使目标 URI 中的参数具有 选择操作的效果时,资源所有者有责任确保 该操作与请求方法语义一致。例如,基于 Web 的内容编辑软件通常会在查询 参数中使用操作,例如 "page?do=delete"。如果此类资源的目的是 执行不安全操作,那么资源所有者在使用安全请求方法访问时必须 禁用或不允许该操作。 如果不这样做,当自动过程 为了链接维护、预取、构建搜索索引等目的对每个 URI 引用执行 GET 时,就会产生不良副作用。

9.2.2. 幂等方法

如果使用某方法的多个相同请求对服务器产生的预期 效果与单个此类请求的效果相同,则认为该请求方法是幂等的。 在本规范定义的请求方法中,PUT、DELETE 和安全请求 方法是幂等的。

与安全的定义一样,幂等属性仅适用于用户 请求的内容;服务器可以自由地分别记录每个请求、保留 修订控制历史,或为每个 幂等请求实现其他非幂等副作用。

之所以区分幂等方法,是因为如果在客户端能够读取 服务器响应之前发生通信故障,请求可以自动重复 。例如,如果客户端发送 PUT 请求,而 底层连接在收到任何响应之前关闭,那么客户端可以 建立新连接并重试幂等请求。它知道重复 请求将具有相同的预期效果,即使原始请求 已成功,尽管响应可能不同。

除非客户端有某种方式知道请求语义 实际上是幂等的,而不管方法如何,或者有某种方式检测到 原始请求从未被应用,否则客户端不应该自动重试具有非幂等方法的请求 。

例如,如果用户代理知道 (通过设计或配置) 请求对于该资源是安全的,它可以自动重复 POST 请求。 同样,专门设计用于操作版本控制 存储库的用户代理,可以通过在连接失败后检查 目标资源的修订版本、撤销或修复任何 部分应用的更改,然后自动重试失败的请求, 从部分故障状况中恢复。

某些客户端采用风险更高的方法,尝试猜测何时可以 自动重试。例如,如果在收到响应的任何部分之前 底层传输连接关闭, 特别是在使用空闲持久连接时,客户端可能会自动重试 POST 请求。

代理不得自动重试非幂等请求。 客户端不应该自动重试失败的自动 重试。

9.2.3. 方法和缓存

要让缓存存储并使用响应,相关方法需要明确 允许缓存,并详细说明响应可在什么条件下用于满足 后续请求;未这样做的方法定义不能被缓存。有关 其他要求,请参见 [CACHING]。

本规范为 GET、HEAD 和 POST 定义了缓存语义,尽管 绝大多数缓存实现只支持 GET 和 HEAD。

9.3. 方法定义

9.3.1. GET

GET 方法请求传输目标资源的当前选定表示。成功响应反映 目标 URI 所标识的 "同一性" 质量 (第 1.2.2 节,见 [URI])。 因此,通过 HTTP 检索可标识信息通常是通过对与在 200 (OK) 响应中提供该 信息的可能性相关联的标识符发出 GET 请求来完成。

GET 是信息检索的主要机制,也是几乎所有 性能优化的重点。为每个重要 资源生成 URI 的应用程序可以从这些优化中受益,同时允许其他 应用程序复用它们,从而产生促进 Web 进一步扩展的网络效应。

人们很容易将资源标识符看作远程文件系统路径名,并 将表示看作此类文件内容的副本。实际上,许多资源 确实如此实现 (有关相关 安全考虑,请参见 第 17.3 节)。但是,实际中并不存在此类限制。

资源的 HTTP 接口同样可能实现为 内容对象树、各种数据库记录的编程视图,或通往 其他信息系统的网关。即使 URI 映射机制绑定到文件 系统,源服务器也可能配置为以请求作为 输入执行文件,并将输出作为表示发送,而不是直接传输文件 。无论如何,只有源服务器需要知道每个资源 标识符如何对应于一个实现,以及该实现如何 选择并发送目标资源的当前表示。

客户端可以通过在请求中发送 Range 头字段 (第 14.2 节), 将 GET 的语义更改为 "范围请求",仅请求传输选定表示的某些部分 。

尽管请求消息分帧与所使用的方法无关,但 GET 请求中接收到的内容 没有普遍定义的语义,不能改变请求的含义或 目标,并且由于其可能被用于请求走私攻击,可能导致某些实现拒绝请求并 关闭连接 (第 11.2 节 ,见 [HTTP/1.1])。除非 GET 请求直接发往一个先前已通过带内或带外方式表明此类请求 有用途并会得到充分支持的 源服务器,否则客户端不应该在 GET 请求中生成内容。源服务器不应该依赖私有协议来接收内容, 因为 HTTP 通信参与者通常不知道请求链上的 中间方。

GET 请求的响应是可缓存的;除非 Cache-Control 头字段另有指示 (第 5.2 节,见 [CACHING]),缓存可以使用它 来满足后续 GET 和 HEAD 请求。

当使用一种从用户提供的信息构造目标 URI 的机制执行信息检索时, 例如使用 GET 的表单查询字段, 可能会提供不适合在 URI 中 披露的潜在敏感数据 (参见 第 17.9 节)。在某些 情况下,可以过滤或转换数据,使其不会泄露此类 信息。在其他情况下,特别是在缓存 响应没有好处时,使用 POST 方法 (第 9.3.3 节) 而不是 GET,可以在 请求内容中传输此类信息,而不是放在目标 URI 中。

9.3.3. POST

POST 方法请求目标 资源根据资源自身的特定语义处理请求中包含的表示 。例如,POST 用于以下 功能 (以及其他功能):

  • 向数据处理过程提供一块数据,例如输入 HTML 表单的字段 ;
  • 向公告板、新闻组、邮件列表、博客或类似 文章组发布消息;
  • 创建尚未由源服务器标识的新资源;以及
  • 向资源的现有表示追加数据。

源服务器根据处理 POST 请求的结果选择适当的状态码来表示响应语义 ;本规范定义的几乎所有状态 码都可能在 POST 响应中收到 (例外是 206 (部分内容)、304 (未修改) 和 416 (范围不可满足))。

如果成功处理 POST 请求后在源服务器上创建了一个或多个资源, 源服务器应该发送 201 (已创建) 响应,其中包含提供所创建 主要资源标识符的 Location 头字段 (第 10.2.2 节),以及在引用新资源时描述 请求状态的表示。

仅当 POST 请求的响应包含显式新鲜度 信息 (参见 第 4.2.1 节,见 [CACHING]),以及 与 POST 目标 URI 具有相同值的 Content-Location 头字段 (第 8.7 节) 时才可缓存。缓存的 POST 响应可复用于满足后续 GET 或 HEAD 请求。相比之下,POST 请求不能由缓存的 POST 响应满足, 因为 POST 可能不安全;参见 第 4 节,见 [CACHING]。

如果处理 POST 的结果等价于现有资源的表示, 源服务器可以通过发送 303 (查看 其他) 响应,并在 Location 字段中放入现有资源的标识符,将用户 代理重定向到该资源。这样做的好处是 为用户代理提供资源标识符,并通过更适合共享缓存的方法传输表示 ,代价是在用户代理尚未缓存该表示时需要额外请求 。

9.3.4. PUT

PUT 方法请求使用请求消息内容中所包含表示定义的状态 创建或替换目标资源的状态。成功 PUT 给定表示 表明随后对同一目标 资源执行 GET 将在 200 (OK) 响应中发送等价表示。但是,并不 保证这种状态变化可以观察到,因为目标资源 可能在收到任何后续 GET 之前被其他用户代理并行操作, 或受到源服务器的动态 处理。成功 响应仅意味着用户代理的意图在源服务器处理该请求时得以实现 。

如果目标资源当前没有表示,并且 PUT 成功创建了一个表示,则源服务器必须通过发送 201 (已创建) 响应告知用户代理。如果目标资源确实有当前表示,并且该 表示按照所包含表示的状态成功修改,则源服务器必须发送 200 (OK) 或 204 (无内容) 响应,以指示 请求成功完成。

源服务器应该验证 PUT 表示 是否与其为目标资源配置的约束一致。例如,如果 源服务器根据 URI 确定资源的表示元数据, 那么源服务器需要确保成功 PUT 请求中收到的内容与该元数据一致。当 PUT 表示与 目标资源不一致时,源服务器应该通过转换表示或更改资源 配置使其一致,或者以包含足够 信息说明表示为何不合适的适当错误消息响应。建议使用 409 (冲突) 或 415 (不支持的媒体类型) 状态码,后者 专用于对 Content-Type 值的约束。

例如,如果目标资源配置为始终具有 Content-Type "text/html",而 被 PUT 的表示具有 Content-Type "image/jpeg",则源服务器应当 执行以下一种操作:

  1. 重新配置目标资源以反映新的媒体类型;
  2. 在将 PUT 表示保存为新的资源状态之前,将其转换为与 资源一致的格式;或者,
  3. 以 415 (不支持的 媒体类型) 响应拒绝请求,指出目标资源仅限于 "text/html",还可以包含指向适合作为新表示 目标的其他资源的链接。

除用户代理请求的意图和 源服务器响应的语义可以表达的内容之外,HTTP 并不精确定义 PUT 方法如何影响源服务器状态 。它不会在 HTTP 提供的接口之外以任何意义定义资源可能 是什么。它不会 定义资源状态如何被 "存储",也不会定义这种存储如何因 资源状态变化而改变,也不会定义源服务器如何将资源状态 转换为表示。一般而言,资源 接口背后的所有实现细节都由服务器有意隐藏。

这也适用于头字段和尾部字段的存储方式;虽然像 Content-Type 这样的常见头字段通常会 被存储,并在后续 GET 请求时返回,但头字段和尾部字段的处理 特定于接收请求的资源。因此,源服务器 应该忽略 PUT 请求中收到的无法识别的头字段和尾部字段 (即,不将它们保存为资源状态的一部分)。

除非请求的表示数据在内容未经任何转换的情况下保存 (即,资源的新表示数据与 PUT 请求中收到的内容完全相同),并且验证器字段值反映新的 表示,否则源服务器在对 PUT 的成功响应中不得发送验证器字段 (第 8.8 节),例如 ETag 或 Last-Modified 字段。这一要求使用户代理能够知道其发送 (并保留在内存中) 的表示就是 PUT 的结果,因此无需 再从源服务器检索。响应中收到的新验证器 可用于未来的条件请求,以防止意外 覆盖 (第 13.1 节)。

POST 和 PUT 方法之间的根本区别体现在 对所包含表示的不同意图上。POST 请求中的目标资源旨在根据资源自身的语义处理所包含的表示 ,而 PUT 请求中所包含的表示 被定义为替换目标资源的状态。因此,PUT 的意图是 幂等的,并对中间方可见,即使确切效果只有 源服务器知道。

正确解释 PUT 请求的前提是用户代理知道想要哪个 目标资源。在收到状态更改请求后代表客户端选择适当 URI 的服务 应该使用 POST 方法而不是 PUT 实现。如果源服务器不会 对目标资源执行所请求的 PUT 状态更改,而是希望 将其应用于不同资源,例如资源已移动到 不同 URI,那么源服务器必须发送适当的 3xx (重定向) 响应;然后用户代理可以自行决定是否 重定向请求。

应用于目标资源的 PUT 请求可能对其他 资源产生副作用。例如,一篇文章可能有一个用于标识 "当前 版本" (一个资源) 的 URI,它与标识各个特定 版本的 URI 分开 (这些不同资源曾经与当前 版本资源共享相同状态)。因此,对 "当前版本" URI 的成功 PUT 请求 可能除了改变目标资源状态之外,还会创建一个新版本资源 ,并且还可能导致在相关 资源之间添加链接。

某些源服务器支持将 Content-Range 头字段 (第 14.4 节) 用作 请求修饰符来执行部分 PUT,如 第 14.5 节所述。

PUT 方法的响应不可缓存。如果成功的 PUT 请求经过 一个为目标 URI 存储了一个或多个响应的缓存,则这些 存储的响应将失效 (参见 第 4.4 节,见 [CACHING])。

9.3.5. DELETE

DELETE 方法请求源服务器移除目标资源与其当前 功能之间的关联。实际上,此方法类似于 UNIX 中的 "rm" 命令:它 表示对源服务器 URI 映射执行删除操作,而不是 期望删除先前关联的信息。

如果目标资源具有一个或多个当前表示,源服务器可能销毁这些表示,也可能不销毁 ,并且相关存储可能被回收,也可能不被回收 ,这完全取决于资源的性质以及源服务器对它的 实现 (这些超出本规范范围)。同样,资源的其他实现方面可能需要 因 DELETE 而停用或归档,例如数据库或网关 连接。一般而言,假定源服务器仅允许对具有规定删除机制的资源执行 DELETE 。

允许 DELETE 方法的资源相对较少——它主要用于远程 创作环境,在那里用户对其效果具有一定控制。例如, 先前使用 PUT 请求创建的资源,或在对 POST 请求的 201 (已创建) 响应后通过 Location 头字段标识的资源,可以允许相应的 DELETE 请求撤销这些操作。同样,实现创作功能的自定义用户代理实现, 例如使用 HTTP 进行 远程操作的版本控制客户端,可以基于服务器 URI 空间被设计为与版本存储库对应的假设使用 DELETE。

如果 DELETE 方法成功应用,则源服务器应该发送

  • 如果操作很可能成功但尚未执行,则发送 202 (已接受) 状态码 ,
  • 如果操作已经执行并且不再提供其他信息,则发送 204 (无内容) 状态码 ,或者
  • 如果操作已经执行并且响应消息包含描述 状态的表示,则发送 200 (OK) 状态码。

尽管请求消息分帧与所使用的方法无关,但 DELETE 请求中接收到的内容 没有普遍定义的语义,不能改变请求的含义或 目标,并且由于其可能被用于请求走私攻击,可能导致某些实现拒绝请求并 关闭连接 (第 11.2 节 ,见 [HTTP/1.1])。除非 DELETE 请求直接发往一个先前已通过带内或带外方式表明此类请求 有用途并会得到充分支持的 源服务器,否则客户端不应该在 DELETE 请求中生成内容。源服务器不应该依赖私有协议来接收内容, 因为 HTTP 通信参与者通常不知道请求链上的 中间方。

DELETE 方法的响应不可缓存。如果成功的 DELETE 请求 经过一个为目标 URI 存储了一个或多个响应的缓存, 这些存储的响应将失效 (参见 第 4.4 节,见 [CACHING])。

9.3.6. CONNECT

CONNECT 方法请求接收方建立到请求目标所标识的目的地 源服务器的隧道,并且如果成功,此后 将其行为限制为在两个方向上盲目转发数据,直到 隧道关闭。隧道通常用于通过一个或多个代理创建端到端虚拟 连接,然后可以使用 TLS (传输层安全性,[TLS13]) 对其进行保护。

CONNECT 使用一种此方法独有的特殊请求目标形式,仅由 隧道目的地的主机和端口号组成,两者以冒号分隔。没有 默认端口;即使 CONNECT 请求基于一个 authority 组件省略了端口的 URI 引用,客户端必须发送端口号 (第 4.1 节)。例如,

CONNECT server.example.com:80 HTTP/1.1
Host: server.example.com

服务器必须拒绝以空端口号 或无效端口号为目标的 CONNECT 请求,通常通过以 400 (错误请求) 状态 码响应。

由于 CONNECT 改变 HTTP 连接的请求/响应性质,特定 HTTP 版本可能有不同方式将其语义映射到协议的 线路格式。

CONNECT 旨在用于发往代理的请求。接收方可以通过直接连接到请求目标所标识的服务器 来建立隧道, 或者如果配置为使用另一个代理,则将 CONNECT 请求转发到 下一个入站代理。源服务器可以接受 CONNECT 请求,但大多数源服务器不实现 CONNECT。

任何 2xx (成功) 响应都表示 发送方 (以及所有入站代理) 将在 响应头部部分之后立即切换到隧道模式;该头部部分之后收到的数据来自 请求目标所标识的服务器。成功 响应之外的任何响应都表示隧道尚未形成。

当隧道中间方检测到任一侧关闭其 连接时,隧道关闭:中间方必须尝试将来自关闭一侧的任何 尚未发送的数据发送到另一侧,关闭两个 连接,然后丢弃任何仍未传递的数据。

可以使用代理身份验证来建立创建隧道的权限。例如,

CONNECT server.example.com:443 HTTP/1.1
Host: server.example.com:443
Proxy-Authorization: basic aGVsbG86d29ybGQ=

建立到任意服务器的隧道存在重大风险, 尤其是当目的地是并非用于 Web 流量的知名或保留 TCP 端口时。例如,CONNECT 到 "example.com:25" 表明 代理应连接到为 SMTP 流量保留的端口;如果允许,这可能 诱使代理中继垃圾邮件。支持 CONNECT 的代理应该将其使用限制为一组有限的已知端口或一个 可配置的安全请求目标列表。

服务器在对 CONNECT 的 2xx (成功) 响应中不得发送任何 Transfer-Encoding 或 Content-Length 头字段。客户端 必须忽略在 CONNECT 的成功响应中收到的任何 Content-Length 或 Transfer-Encoding 头字段。

CONNECT 请求消息没有内容。CONNECT 请求消息 头部部分之后发送的数据如何解释取决于所使用的 HTTP 版本。

CONNECT 方法的响应不可缓存。

9.3.7. OPTIONS

OPTIONS 方法请求有关目标资源可用通信选项的信息, 该资源位于源服务器或介入的中间方上。 此方法允许客户端确定与资源相关的选项和/或要求 ,或者服务器的能力,而不暗示资源 操作。

以星号 ("*") 作为请求目标的 OPTIONS 请求 (第 7.1 节) 一般适用于服务器,而不是特定资源。由于 服务器的通信选项通常取决于资源,"*" 请求 仅作为 "ping" 或 "无操作" 类型的方法有用;除了允许 客户端测试服务器的能力之外,它什么都不做。例如,这可以用于 测试代理是否符合 HTTP/1.1。

如果请求目标不是星号,则 OPTIONS 请求适用于与目标资源 通信时可用的选项。

生成对 OPTIONS 的成功响应的服务器应该 发送任何可能指示服务器实现且 适用于目标资源的可选特性的头字段 (例如,Allow),包括本 规范未定义的潜在扩展。响应内容 (如果有) 也可以以机器或人类可读的表示形式描述通信 选项。本规范未为此类 表示定义标准格式,但 HTTP 的未来 扩展可能会定义。

客户端可以在 OPTIONS 请求中发送 Max-Forwards 头字段,以针对请求链中的 特定接收方 (参见 第 7.6.2 节)。除非请求在收到时带有 Max-Forwards 字段, 否则代理在转发请求时不得生成 Max-Forwards 头字段。

生成包含内容的 OPTIONS 请求的客户端必须发送有效的 Content-Type 头字段,描述表示的媒体 类型。请注意,本规范没有定义此类内容的任何用途。

OPTIONS 方法的响应不可缓存。

9.3.8. TRACE

TRACE 方法请求对请求 消息执行远程应用层环回。请求的最终接收方应该将 收到的消息 (排除下面描述的一些字段) 作为 200 (OK) 响应的内容反射 回客户端。 "message/http" 格式 (第 10.1 节,见 [HTTP/1.1]) 是一种 实现方式。最终接收方要么是源服务器,要么是第一个在请求中 收到 Max-Forwards 值为零 (0) 的服务器 (第 7.6.2 节)。

客户端不得在 TRACE 请求中生成 包含可能由响应披露的敏感数据的字段。例如, 用户代理在 TRACE 请求中发送已存储的用户凭据 (第 11 节) 或 Cookie [COOKIE] 是愚蠢的。 请求的最终接收方在生成响应内容时应该排除 任何可能包含敏感数据的请求字段。

TRACE 允许客户端查看请求链另一端接收到的内容, 并将该数据用于测试或诊断信息。Via 头字段的值 (第 7.6.3 节) 特别 有用,因为它充当请求链的跟踪记录。使用 Max-Forwards 头字段允许 客户端限制请求链的长度,这对于测试 在无限循环中转发消息的代理链很有用。

客户端不得在 TRACE 请求中发送内容。

TRACE 方法的响应不可缓存。

10. 消息 上下文

10.1. 请求上下文字段

下面的请求头字段提供有关请求上下文的附加信息, 包括有关用户、用户代理以及请求背后的资源的信息。

10.1.1. Expect

请求中的 "Expect" 头字段指示服务器为了正确处理 此请求而需要支持的一组特定行为 (期望)。

Expect 字段值不区分大小写。

本规范定义的唯一期望是 "100-continue" (没有定义 参数)。

收到包含 100-continue 之外成员的 Expect 字段值的服务器可以 以 417 (期望失败) 状态码响应,表示无法满足意外的期望。

100-continue 期望告知接收方,客户端即将在此请求中 发送 (可能很大的) 内容,并且如果 方法、目标 URI 和头字段不足以引发立即 成功、重定向或错误响应,则希望收到 100 (继续) 临时响应。这允许客户端在实际发送内容之前等待一个 表明发送内容值得的指示,当数据很大或客户端预计 很可能发生错误时,这可以提高效率 (例如,第一次发送状态更改方法 ,且事先未验证身份验证凭据)。

例如,以以下内容开头的请求

PUT /somewhere/fun HTTP/1.1
Host: origin.example.com
Content-Type: video/h264
Content-Length: 1234567890987
Expect: 100-continue

允许源服务器在客户端开始用不必要的数据传输填满 管道之前立即以错误消息响应,例如 401 (未授权) 或 405 (方法不允许)。

客户端要求:

  • 客户端在不包含内容的请求中不得生成 100-continue 期望 。
  • 在发送请求内容之前将等待 100 (继续) 响应的客户端必须发送包含 100-continue 期望的 Expect 头字段。
  • 发送 100-continue 期望的客户端不需要等待任何 特定时长;即使尚未收到响应,此类客户端可以继续 发送内容。此外,由于 100 (继续) 响应不能通过 HTTP/1.0 中间方发送,此类客户端在发送内容之前不应该 无限期等待。
  • 客户端收到针对包含 100-continue 期望的请求的 417 (期望 失败) 状态码时,应该在没有 100-continue 期望的情况下重复该请求,因为 417 响应仅表示 响应链不支持期望 (例如,它经过一个 HTTP/1.0 服务器)。

服务器要求:

  • 服务器收到 HTTP/1.0 请求中的 100-continue 期望时必须忽略该期望。
  • 如果服务器已经收到相应请求的部分或全部内容, 或者分帧表明没有内容,则服务器可以省略发送 100 (继续) 响应。
  • 发送 100 (继续) 响应的服务器在收到并处理请求内容后必须最终发送最终状态码 ,除非连接过早关闭 。
  • 在读取完整请求内容之前以最终状态码响应的服务器应该指示其是否打算 关闭连接 (例如,参见 第 9.6 节,见 [HTTP/1.1]),或者 继续读取请求内容。

收到一个 HTTP/1.1 (或更高版本) 请求时,如果该请求具有方法、目标 URI 和 完整头部部分,其中包含 100-continue 期望以及 后续将有请求内容的指示,则源服务器必须发送 以下之一:

  • 如果仅检查方法、目标 URI 和头字段即可确定最终状态,则立即 以最终状态码响应,或者
  • 立即发送 100 (继续) 响应,以 鼓励客户端发送请求内容。

源服务器在发送 100 (继续) 响应之前不得等待内容。

收到一个 HTTP/1.1 (或更高版本) 请求时,如果该请求具有方法、目标 URI 和 完整头部部分,其中包含 100-continue 期望并指示 后续将有请求内容,则代理必须执行以下之一:

  • 如果仅检查方法、目标 URI 和头字段即可 确定最终状态,则立即以最终状态码响应,或者
  • 通过向下一个入站服务器发送相应的 请求行和头部部分,将请求转发向源服务器。

如果代理认为 (根据配置或过去的交互) 下一个入站 服务器仅支持 HTTP/1.0,则代理可以立即生成 100 (继续) 响应,以 鼓励客户端开始发送内容。

10.1.2. From

"From" 头字段包含控制请求用户代理的人类用户的 Internet 电子邮件地址 。该地址应当可供机器使用,如 第 3.4 节 中 [RFC5322] 的 "mailbox" 所定义:

  From    = mailbox

  mailbox = <mailbox, see [RFC5322], Section 3.4>

示例如下:

From: spider-admin@example.org

非机器人用户代理很少发送 From 头字段。用户代理在没有用户明确 配置的情况下不应该发送 From 头字段,因为这可能与用户的隐私 利益或其站点的安全策略冲突。

机器人用户代理应该发送有效的 From 头字段,以便 当服务器出现问题时可以联系负责运行机器人的人 ,例如机器人发送过多、不需要或无效的 请求。

服务器不应该将 From 头字段用于访问 控制或身份验证,因为预期任何 接收或观察请求的人都能看到其值,并且它通常会被记录在日志文件和错误 报告中,而不带任何隐私预期。

10.1.3. Referer

"Referer" [原文如此] 头字段允许用户代理指定一个 URI 引用,用于表示 获取目标 URI的资源 (即 "referrer",尽管字段名称拼写错误)。用户 代理在生成 Referer 字段值时不得包含 URI 引用的片段和 userinfo 组件 [URI], 如果存在。

字段值要么是 absolute-URI ,要么是 partial-URI。在后一种情况下 (第 4 节),所引用的 URI 相对于目标 URI ([URI], 第 5 节)。

Referer 头字段允许服务器生成指向其他资源的反向链接,用于 简单分析、日志记录、优化缓存等。它还允许发现过时或 拼写错误的链接以进行维护。某些服务器将 Referer 头 字段用作拒绝其他站点链接 (所谓的 "深层链接") 或 限制跨站请求伪造 (CSRF) 的手段,但并非所有请求都包含它。

示例:

Referer: http://www.example.org/hypertext/Overview.html

如果目标 URI 是从自身没有 URI 的来源获得的 (例如, 用户键盘输入,或用户书签/收藏夹中的条目), 用户代理必须排除 Referer 头字段 或以值 "about:blank" 发送它。

Referer 头字段值无需传达引用 资源的完整 URI;用户代理可以截断除 引用源之外的部分。

Referer 头字段可能泄露有关请求 上下文或用户浏览历史的信息,如果引用 资源的标识符泄露个人信息 (例如账户名称) 或 本应保密的资源 (例如防火墙后面或安全 服务内部的资源),这会造成隐私问题。大多数通用用户代理在引用资源是本地 "file" 或 "data" URI 时不会发送 Referer 头字段。如果引用资源通过安全协议访问,并且请求目标的源不同于引用 资源的源,则用户 代理不应该发送 Referer 头字段,除非引用资源明确允许发送 Referer 。如果引用资源通过安全协议访问,用户代理在不安全的 HTTP 请求中不得发送 Referer 头字段。有关 其他安全考虑,请参见 第 17.9 节。

已知某些中间方会不加区分地从传出请求中删除 Referer 头字段 。这会产生不良副作用,干扰 针对 CSRF 攻击的防护,而这种攻击对用户的危害可能更大。 希望限制 Referer 中信息披露的中间方和用户代理扩展 应当将其修改限制为特定编辑,例如将 内部域名替换为假名,或截断查询和/或路径 组件。当字段值与 目标 URI 具有相同方案和主机时,中间方不应该修改或删除 Referer 头字段。

10.1.4. TE

"TE" 头字段描述客户端在传输 编码和尾部部分方面的能力。

如 第 6.5 节所述, 请求中发送的、包含 "trailers" 成员的 TE 字段表示客户端不会 丢弃尾部字段。

TE 还用于 HTTP/1.1 中,以告知服务器客户端 能够在响应中接受哪些传输编码。截至发布时,只有 HTTP/1.1 使用 传输编码 (参见 第 7 节,见 [HTTP/1.1])。

TE 字段值是成员列表,每个成员 (除 "trailers" 外) 由一个传输编码名称令牌组成,可带一个可选权重,表示 客户端对该传输编码的相对偏好 (第 12.4.2 节),以及该 传输编码的可选参数。

TE 的发送方必须同时在 Connection 头字段中发送 "TE" 连接选项 (第 7.6.1 节),以通知中间方不要转发 此字段。

10.1.5. User-Agent

"User-Agent" 头字段包含有关发起 请求的用户代理的信息,服务器通常使用这些信息帮助识别所报告 互操作性问题的范围、规避或调整响应以避免特定 用户代理限制,以及分析浏览器或操作系统使用情况。 除非明确配置为不这样做,否则用户代理在每个 请求中应该发送 User-Agent 头字段。

User-Agent 字段值由一个或多个产品标识符组成,每个标识符后面 跟零个或多个注释 (第 5.6.5 节), 它们共同标识用户代理软件及其重要子产品。按照 约定,产品标识符按其对 标识用户代理软件的重要性递减顺序列出。每个产品标识符 由名称和可选版本组成。

发送方应该将生成的产品标识符限制为 标识产品所必需的内容;发送方不得在产品标识符中生成 广告或其他非必要信息。 发送方不应该在 product-version 中生成不是版本 标识符的信息 (即,同一产品名称的连续版本应当仅 在产品标识符的 product-version 部分不同)。

示例:

User-Agent: CERN-LineMode/2.15 libwww/2.17b3

用户代理不应该生成 包含不必要细粒度详细信息的 User-Agent 头字段,并且应该限制 第三方添加子产品。过长且详细的 User-Agent 字段值会增加请求延迟以及用户违背其意愿被识别 ("指纹识别") 的风险。

同样,鼓励实现不要使用其他 实现的产品令牌来声明与其兼容,因为这会规避 该字段的目的。如果用户代理伪装成另一个用户代理, 接收方可以假定用户有意希望看到为该已标识用户代理定制的响应 ,即使这些响应对实际 使用的用户代理可能运行得不那么好。

10.2. 响应上下文字段

下面的响应头字段提供有关响应的附加信息, 超出状态码所隐含的内容,包括有关服务器、 目标资源或相关 资源的信息。

10.2.1. Allow

"Allow" 头字段列出目标资源宣告支持的方法集合。此 字段的目的严格是告知接收方与 该资源相关的有效请求方法。

使用示例:

Allow: GET, HEAD, PUT

实际允许的方法集合由源服务器在每次 请求时定义。源服务器在 405 (方法不允许) 响应中必须生成 Allow 头字段,并且在任何其他响应中 可以这样做。空 Allow 字段值 表示资源不允许任何方法,例如当资源因配置而暂时禁用时, 这种情况可能出现在 405 响应中。

代理不得修改 Allow 头字段——它无需 理解所有指示的方法,也可以根据 通用消息处理规则处理它们。

10.2.2. Location

"Location" 头字段用于某些响应中,以引用与响应相关的特定资源 。关系类型由请求方法 和状态码语义的组合定义。

字段值由单个 URI-reference 组成。当它采用 相对引用形式时 ([URI], 第 4.2 节), 最终值通过相对于目标 URI 解析它来计算 ([URI], 第 5 节)。

对于 201 (已创建) 响应,Location 值引用请求创建的主要资源。对于 3xx (重定向) 响应,Location 值引用用于自动重定向 请求的首选目标资源。

如果 3xx (重定向) 响应中提供的 Location 值没有片段组件,则用户代理必须像该值继承 用于生成目标 URI 的 URI 引用的片段组件一样处理重定向 (即, 重定向继承原始引用的片段,如果有)。

例如,为 URI 引用 "http://www.example.org/~tim" 生成的 GET 请求可能得到一个 303 (查看其他) 响应,其中包含头字段:

Location: /People.html#tim

这表示建议用户代理重定向到 "http://www.example.org/People.html#tim"

同样,为 URI 引用 "http://www.example.org/index.html#larry" 生成的 GET 请求可能得到一个 301 (永久移动) 响应,其中包含头字段:

Location: http://www.example.net/index.html

这表示建议用户代理重定向到 "http://www.example.net/index.html#larry",并保留原始片段 标识符。

在某些情况下,Location 值中的片段标识符并不 合适。例如,201 (已创建) 响应中的 Location 头字段应该提供一个 特定于所创建资源的 URI。

10.2.3. Retry-After

服务器发送 "Retry-After" 头字段来指示用户代理在 发出后续请求之前应当等待多长时间。与 503 (服务不可用) 响应一起发送时,Retry-After 指示 服务预计对客户端不可用的时长。与任何 3xx (重定向) 响应一起发送时,Retry-After 指示要求用户代理在发出 重定向请求之前等待的最短时间。

Retry-After 字段值可以是 HTTP-date,也可以是收到响应后要 延迟的秒数。

delay-seconds 值是非负十进制整数, 表示以秒为单位的时间。

其使用的两个示例是

Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Retry-After: 120

在后一个示例中,延迟为 2 分钟。

10.2.4. Server

"Server" 头字段包含有关源服务器用于处理 请求的软件的信息,客户端通常使用这些信息帮助识别所报告 互操作性问题的范围、规避或调整请求以 避免特定服务器限制,以及分析服务器或操作 系统的使用情况。源服务器可以在其响应中生成 Server 头 字段。

Server 头字段值由一个或多个产品标识符组成,每个标识符后面 跟零个或多个注释 (第 5.6.5 节),它们共同标识源服务器软件及其 重要子产品。按照约定,产品标识符按其 对标识源服务器软件的重要性递减顺序列出。 每个产品标识符由名称和可选版本组成,如 第 10.1.5 节中所定义。

示例:

Server: CERN/3.0 libwww/2.17

源服务器不应该生成 包含不必要细粒度详细信息的 Server 头字段,并且应该限制 第三方添加子产品。过长且详细的 Server 字段 值会增加响应延迟,并可能泄露内部实现 细节,从而使攻击者 (稍微) 更容易发现和利用已知 安全漏洞。

11. HTTP 身份验证

11.1. 身份验证方案

HTTP 通过一组可扩展的质询-响应身份验证方案, 提供了访问控制和身份验证的通用框架,服务器可以使用这些方案 质询客户端请求,客户端也可以使用这些方案提供身份验证 信息。它使用不区分大小写的令牌来标识身份验证方案:

  auth-scheme    = token

除通用框架外,本文不规定任何身份验证 方案。新的和现有的身份验证方案独立规定,并应当 注册到“超文本传输协议 (HTTP) 身份验证方案 注册表”中。例如,“basic”和“digest”身份验证方案分别由 [RFC7617] 和 [RFC7616]定义。

11.2. 身份验证参数

身份验证方案后跟通过该方案实现身份验证所必需的附加信息, 这些信息可以是逗号分隔的参数列表,也可以是 能够容纳 base64 编码信息的单个字符序列。

  token68        = 1*( ALPHA / DIGIT /
                       "-" / "." / "_" / "~" / "+" / "/" ) *"="

token68 语法允许使用 66 个非保留 URI 字符([URI]), 再加上少量其他字符,因此它可以容纳带或不带填充的 base64、base64url(URL 和文件名安全 字母表)、base32 或 base16(十六进制)编码,但不包括 空白([RFC4648])。

身份验证参数是名称/值对,其中名称令牌以 不区分大小写的方式进行匹配,并且每个参数名称在每个质询中必须仅出现一次。

  auth-param     = token BWS "=" BWS ( token / quoted-string )

参数值可以表示为“token”或“quoted-string”(第 5.6 节)。身份验证方案定义需要同时接受这两种表示法,无论对于 发送方还是接收方,以允许接收方不论身份验证方案为何都使用通用解析组件 。

为了向后兼容,身份验证方案定义可以将发送方的格式 限制为这两种变体中的一种。当已知 已部署实现遇到这两种格式之一时会失败,这一点可能很重要。

11.3. 质询和响应

源服务器使用 401(未授权)响应消息 质询用户代理的授权,其中包括一个 WWW-Authenticate 头字段, 该字段包含至少一个适用于所请求资源的质询。

代理使用 407(需要代理身份验证)响应 消息质询客户端的授权,其中包括一个 Proxy-Authenticate 头字段, 该字段包含至少一个适用于所请求资源之代理的质询。

希望向源服务器验证自身身份的用户代理——通常但不 一定是在收到 401(未授权) 响应之后——可以通过在请求中包含 Authorization 头字段来实现。

希望向代理验证自身身份的客户端——通常但不一定 是在收到 407(需要代理身份验证) 之后——可以通过在请求中包含 Proxy-Authorization 头字段来实现。

11.4. 凭据

Authorization 字段值和 Proxy-Authorization 字段 值都包含客户端针对所请求资源 realm 的凭据, 这些凭据基于响应中收到的质询(可能是过去某个时间收到的)。在 创建这些值时,用户代理应当选择 其理解的、认为最安全的 auth-scheme 所对应的质询,并在适当时从用户处获取 凭据。在头 字段值中传输凭据意味着需要认真考虑底层连接机密性的安全问题, 如 第 17.16.1 节所述。

收到针对受保护资源的请求时,如果请求省略了凭据、包含 无效凭据(例如错误密码)或部分凭据(例如 身份验证方案需要不止一次往返时),源服务器应该发送 401 (未授权)响应,其中包含 WWW-Authenticate 头字段,且至少包含一个(可能是新的) 适用于所请求资源的质询。

同样,收到省略代理凭据或包含无效或 部分代理凭据的请求时,需要身份验证的代理应该生成 407(需要代理 身份验证)响应,其中包含 Proxy-Authenticate 头字段, 且至少包含一个(可能是新的)适用于代理的质询。

收到有效但不足以获得访问权限的凭据时,服务器应当 以 403(禁止)状态码响应(第 15.5.4 节)。

HTTP 不将应用限制在这种简单的质询-响应框架内进行 访问身份验证。还可以使用其他机制,例如传输层 身份验证或通过消息封装进行身份验证,并使用附加头字段 指定身份验证信息。但是,本规范不 定义此类附加机制。

请注意,各种用于用户身份验证的自定义机制使用 [COOKIE]中定义的 Set-Cookie 和 Cookie 头字段来传递与身份验证相关的令牌。

11.5. 建立保护空间(Realm)

realm 身份验证参数保留供希望 指示保护范围的身份验证方案使用。

保护空间由正在访问的服务器的源(参见 第 4.3.1 节)以及 realm 值(如果存在)共同定义 。这些 realm 允许将服务器上的受保护资源 划分为一组保护空间,每个保护空间都有自己的身份验证 方案和/或授权数据库。realm 值是一个字符串,通常由 源服务器分配,可以具有特定于身份验证 方案的附加语义。请注意,一个响应可以具有多个使用相同 auth-scheme 但 realm 不同的质询。

保护空间确定可以自动 应用凭据的域。如果先前的请求已获授权,用户代理可以在由身份验证方案、 参数和/或用户偏好(例如可配置的不活动超时)确定的一段时间内,对该 保护空间内的所有其他请求复用相同凭据。

保护空间的范围,以及因此可能 自动应用凭据的请求,在没有附加 信息的情况下,客户端不一定知道。身份验证方案可以定义描述 保护空间范围的参数。除非身份验证方案明确允许,否则 单个保护空间不能扩展到其服务器范围之外。

由于历史原因,发送方必须仅生成 quoted-string 语法。为了与长期同时接受这两种 表示法的现有客户端实现最大程度互操作,接收方可能必须同时支持 token 和 quoted-string 语法。

11.6. 对源服务器的用户进行身份验证

11.6.1. WWW-Authenticate

“WWW-Authenticate”响应头字段指示适用于目标资源的身份验证方案 及参数。

生成 401(未授权) 响应的服务器必须发送至少包含 一个质询的 WWW-Authenticate 头字段。服务器可以在其他响应消息中生成 WWW-Authenticate 头字段,以指示提供 凭据(或不同凭据)可能会影响响应。

转发响应的代理不得修改该响应中的任何 WWW-Authenticate 头字段。

建议用户代理在解析字段值时格外小心,因为其中可能 包含不止一个质询,并且每个质询可以包含逗号分隔的 身份验证参数列表。此外,头字段本身可以出现 多次。

例如:

WWW-Authenticate: Basic realm="simple", Newauth realm="apps",
                 type=1, title="Login to \"apps\""

该头字段包含两个质询,一个用于 realm 值为“simple”的“Basic”方案,另一个用于 realm 值为“apps”的“Newauth”方案 。它还包含两个附加参数“type”和“title”。

但是,某些用户代理无法识别这种形式。因此,在同一字段行中发送包含多个成员的 WWW-Authenticate 字段值可能 无法互操作。

11.6.2. Authorization

“Authorization”头字段允许用户代理向 源服务器验证自身身份——通常但不一定是在收到 401(未授权)响应之后。其值 由凭据组成,其中包含用户代理针对 所请求资源 realm 的身份验证信息。

如果请求已通过身份验证并指定了 realm,则假定相同的凭据 对此 realm 中的所有其他请求均有效(假设 身份验证方案本身没有其他要求,例如凭据会根据 质询值而变化或使用同步时钟)。

转发请求的代理不得修改该 请求中的任何 Authorization 头字段。有关 HTTP 缓存处理 Authorization 头字段的详细信息和要求,请参见 [CACHING] 的第 3.5 节。

11.6.3. Authentication-Info

HTTP 身份验证方案可以使用“Authentication-Info”响应字段, 在客户端的身份验证凭据被 接受后传达信息。此信息可以包括来自服务器的结束消息(例如, 它可以包含服务器身份验证)。

字段值是参数(名称/值对)列表,使用 第 11.3 节中定义的“auth-param” 语法。本规范仅 描述通用格式;使用 Authentication-Info 的身份验证方案将 定义各个参数。例如,“Digest”身份验证方案 在 第 3.5 节 中 [RFC7616]定义了多个参数。

Authentication-Info 字段可以用于任何 HTTP 响应,而不依赖于 请求方法和状态码。其语义由相应请求的 Authorization 头字段(第 11.6.2 节) 所指示的身份验证方案定义。

转发响应的代理不允许以任何方式修改字段值。

当身份验证方案明确允许时,Authentication-Info 可以作为尾部字段发送(第 6.5 节)。

11.7. 对代理的客户端进行身份验证

11.7.1. Proxy-Authenticate

“Proxy-Authenticate”头字段由至少一个质询组成,该质询 指示适用于此请求代理的身份验证方案和参数 。代理在它生成的每个 407 (需要代理身份验证)响应中必须发送至少一个 Proxy-Authenticate 头字段。

与 WWW-Authenticate 不同, Proxy-Authenticate 头字段仅适用于响应链上的下一个出站客户端 。这是因为只有选择给定代理的客户端才可能 拥有身份验证所需的凭据。但是,当在同一个管理域中使用多个代理时, 例如大型企业网络内的办公室和区域缓存 代理,通常由用户代理生成凭据, 并通过层级传递直至被消费。因此, 在这种配置中,看起来会像 Proxy-Authenticate 被转发 一样,因为每个代理都会发送同一组质询。

请注意,WWW-Authenticate 的解析注意事项也适用于此头字段;有关详细信息,请参见 第 11.6.1 节。

11.7.2. Proxy-Authorization

“Proxy-Authorization”头字段允许客户端向需要身份验证的代理标识自身(或其 用户)。其值由凭据组成, 其中包含客户端针对代理和/或所请求资源 realm 的身份验证信息。

与 Authorization 不同, Proxy-Authorization 头字段仅适用于使用 Proxy-Authenticate 头字段要求身份验证的下一个入站代理 。当链中使用多个代理时,Proxy-Authorization 头字段由第一个 预期接收凭据的入站代理消费。如果这是 代理协同验证给定请求的机制,代理可以 将客户端请求中的凭据中继到下一个代理。

11.7.3. Proxy-Authentication-Info

“Proxy-Authentication-Info”响应头字段等同于 Authentication-Info,但 它适用于代理身份验证(第 11.3 节),并且其语义由相应请求的 Proxy-Authorization 头字段(第 11.7.2 节)所指示的身份验证方案定义:

但是,与 Authentication-Info 不同,Proxy-Authentication-Info 头字段 仅适用于响应链上的下一个出站客户端。这是因为只有 选择给定代理的客户端才可能拥有 身份验证所需的凭据。但是,当在同一个 管理域中使用多个代理时,例如大型 企业网络内的办公室和区域缓存代理,通常由用户代理生成凭据 并通过层级传递直至被消费。因此,在这种配置中, 看起来会像 Proxy-Authentication-Info 被转发一样,因为每个代理 都会发送相同的字段值。

当身份验证方案明确允许时,Proxy-Authentication-Info 可以作为尾部字段发送(第 6.5 节)。

12. 内容协商

当响应传达内容时,无论表示成功还是错误,源服务器 通常都有不同方式表示该信息;例如使用不同的 格式、语言或编码。同样,不同用户或用户代理可能具有 不同能力、特征或偏好,这些因素会影响可用表示中 哪个最适合传递。因此,HTTP 提供了内容协商机制。

本规范定义了三种可在协议中体现的内容协商模式: “主动”协商,其中服务器根据用户代理声明的偏好选择表示; “反应式”协商,其中服务器提供表示列表供用户代理选择; 以及“请求内容”协商,其中用户代理根据服务器在过去响应中声明的偏好 为未来请求选择表示。

其他内容协商模式包括“条件内容”,其中表示 由根据用户代理参数选择性渲染的多个部分组成; “主动内容”,其中表示包含根据用户代理特征发出额外(更 具体)请求的脚本;以及“透明内容 协商”([RFC2295]),其中内容 选择由中间方执行。这些模式并不互斥, 每一种在适用性和实用性方面都有权衡。

请注意,在所有情况下,HTTP 都不了解资源语义。源服务器 随时间以及跨内容协商的不同维度响应请求时的一致性, 以及因此一个资源随时间观察到的表示之间的“同一性”, 完全由选择或生成这些 响应的实体或算法决定。

12.1. 主动协商

当用户代理在请求中发送内容协商偏好,以促使 位于服务器的算法选择首选表示时,这称为 主动协商(又称服务器驱动的协商)。 选择基于响应可用的表示(它可能变化的维度, 例如语言、内容编码等)与请求中提供的各种 信息进行比较,其中包括下面的显式协商头 字段以及隐式特征,例如客户端的网络地址或 User-Agent 字段的部分内容 。

当从可用表示中进行选择的算法难以向用户代理描述, 或者服务器希望在第一次响应中将其“最佳猜测”发送给用户代理时, 主动协商具有优势(当该“最佳猜测”对用户足够好时, 可避免后续请求的往返延迟)。为了提高服务器猜测的准确性,用户代理可以发送描述其偏好的请求头字段。

主动协商存在严重缺点:

  • 服务器不可能准确确定对于任何 给定用户什么可能是“最佳”的,因为这需要完全了解 用户代理的能力以及响应的预期用途(例如,用户是想 在屏幕上查看还是打印到纸上?);
  • 让用户代理在每个请求中描述其能力既可能非常 低效(因为只有很小比例的响应具有多个 表示),也可能对用户隐私造成潜在风险;
  • 它使源服务器的实现以及 为请求生成响应的算法更加复杂;并且,
  • 它限制响应用于共享缓存的可复用性。

用户代理不能依赖主动协商偏好始终得到遵守, 因为源服务器可能没有为所请求的 资源实现主动协商,或者可能认为发送不符合用户 代理偏好的响应比发送 406(不可 接受)响应更好。

在受主动协商影响的响应中通常会发送 Vary 头字段(第 12.5.5 节),以指示请求 信息的哪些部分用于选择算法。

下面定义的请求头字段 Accept、Accept-Charset、Accept-Encoding 和 Accept-Language 用于让 用户代理参与响应内容的主动 协商。这些字段中发送的偏好适用于 响应中的任何内容,包括目标资源的表示、 错误或处理状态的表示,甚至可能包括协议中 出现的各种文本字符串。

12.2. 反应式协商

在反应式协商(又称代理驱动的协商)中, 内容选择(无论状态码如何)由用户代理在 收到初始响应后执行。反应式协商的机制可以简单到 只是一个替代表示引用列表。

如果用户代理对初始响应内容不满意,它可以对 一个或多个替代资源执行 GET 请求以获得不同的 表示。此类替代项的选择可以自动执行(由 用户代理),也可以手动执行(例如,由用户从超文本菜单中选择)。

服务器可以选择不发送初始表示,只发送 替代项列表,从而表明首选用户代理进行反应式协商 。例如,使用 300(多种选择)和 406(不可接受)状态码的响应中列出的替代项包含 有关可用表示的信息,使用户或用户代理可以通过进行 选择作出反应。

当响应会在常用维度(例如类型、语言或编码)上变化, 当源服务器无法通过检查请求确定用户代理的能力, 以及通常在使用公共缓存来分担服务器负载并减少网络使用量时, 反应式协商具有优势。

反应式协商的缺点是需要向用户代理传输 替代项列表,如果该列表在头部部分传输,会降低用户感知的延迟表现, 并且需要第二个请求来获取替代表示。 此外,本规范没有定义支持自动 选择的机制,但也不妨碍开发此类机制。

12.3. 请求内容协商

当内容协商偏好在服务器响应中发送时,列出的 偏好称为请求内容协商,因为它们旨在 影响对该资源后续请求的适当内容选择。 例如,Accept(第 12.5.1 节) 和 Accept-Encoding(第 12.5.3 节)头字段可以在响应中发送, 以指示对该资源后续请求首选的媒体类型和内容编码 。

类似地,[RFC5789] 的第 3.1 节定义了“Accept-Patch” 响应头字段,该字段可以发现 PATCH 请求中接受哪些内容类型。

12.4. 内容协商字段特性

12.4.1. 缺失

对于每个内容协商字段,不包含该字段的请求 表示发送方对该协商维度没有偏好。

如果请求中存在内容协商头字段,并且响应的所有 可用表示根据该字段都不能被视为可接受, 则源服务器可以通过发送 406(不可接受)响应来遵守该头字段,或者 忽略该头字段,将响应视为不受该请求头字段的内容 协商约束。但是,这并不意味着 客户端能够使用该表示。

12.4.2. 质量值

本规范定义的内容协商字段使用一个通用参数, 名为“q”(不区分大小写),用于为 相关内容类型的偏好分配相对“权重”。此权重称为“质量值”(或 “qvalue”),因为在服务器配置中也经常使用相同参数名称 为可为资源选择的各种表示的相对质量分配 权重。

权重被规范化为 0 到 1 范围内的实数,其中 0.001 表示最低偏好,1 表示最高偏好;值 0 表示“不可 接受”。如果不存在“q”参数,则默认权重为 1。

  weight = OWS ";" OWS "q=" qvalue
  qvalue = ( "0" [ "." 0*3DIGIT ] )
         / ( "1" [ "." 0*3("0") ] )

qvalue 的发送方不得在小数点后生成超过三位数字 。用户对这些值的配置也应当以 相同方式加以限制。

12.4.3. 通配符值

这些头字段中的大多数会在指定的位置定义通配符值(“*”)来选择 未指定的值。如果没有通配符,则字段中未明确 提及的值被视为不可接受。在 Vary 中,通配符值意味着变化是无限的。

12.5. 内容协商字段

12.5.1. Accept

用户代理可以使用“Accept”头字段指定其对 响应媒体类型的偏好。例如,Accept 头字段可以用于 表明请求专门限制为一小组所需类型, 例如请求内联图像时。

服务器在响应中发送 Accept 时,它提供有关 对同一资源后续请求的内容中首选哪些内容类型的信息。

  Accept = #( media-range [ weight ] )

  media-range    = ( "*/*"
                     / ( type "/" "*" )
                     / ( type "/" subtype )
                   ) parameters

星号“*”字符用于将媒体类型分组为范围,其中“*/*” 表示所有媒体类型,“type/*”表示该类型的所有子类型。 media-range 可以包含适用于该范围的媒体类型参数。

每个 media-range 后面可以跟可选的适用媒体类型参数 (例如 charset),然后跟一个可选的“q” 参数,用于指示相对权重(第 12.4.2 节)。

以前的规范允许在 weight 参数之后出现附加扩展参数。accept 扩展语法(accept-params、accept-ext)已经 被移除,因为其定义复杂、实际中未被使用,并且 更容易通过新的头字段部署。使用权重的发送方应该最后发送“q”(位于所有 media-range 参数之后)。 接收方应该将任何名为“q”的参数作为 weight 处理, 无论参数顺序如何。

示例

Accept: audio/*; q=0.2, audio/basic

解释为“我更喜欢 audio/basic,但如果在质量降低 80% 后任何音频类型仍是最佳可用选项,也请发送给我”。

更详细的示例是

Accept: text/plain; q=0.5, text/html,
       text/x-dvi; q=0.8, text/x-c

用文字表示,这将解释为“text/html 和 text/x-c 是同等 首选的媒体类型,但如果它们都不存在,则发送 text/x-dvi 表示,如果它也不存在,则发送 text/plain 表示”。

媒体范围可以被更具体的媒体范围或特定媒体类型覆盖。 如果多个媒体范围适用于给定类型,则最具体的引用 优先。例如,

Accept: text/*, text/plain, text/plain;format=flowed, */*

具有以下优先级:

  1. text/plain;format=flowed
  2. text/plain
  3. text/*
  4. */*

与给定类型关联的媒体类型质量因子通过查找 与该类型匹配且优先级最高的媒体范围来确定。例如,

Accept: text/*;q=0.3, text/plain;q=0.7, text/plain;format=flowed,
       text/plain;format=fixed;q=0.4, */*;q=0.5

将产生以下关联值:

表 5
媒体类型 质量值
text/plain;format=flowed 1
text/plain 0.7
text/html 0.3
image/jpeg 0.5
text/plain;format=fixed 0.4
text/html;level=3 0.7

12.5.2. Accept-Charset

用户代理可以发送“Accept-Charset”头字段,以指示其 对文本响应内容中字符集的偏好。例如,此字段允许 能够理解更全面或特殊用途字符集的用户代理 向能够用这些字符集表示 信息的源服务器表明该能力。

  Accept-Charset = #( ( token / "*" ) [ weight ] )

字符集名称定义于 第 8.3.2 节。用户代理可以为每个字符集关联一个质量值, 以指示用户对该字符集的相对偏好,如 第 12.4.2 节所定义。示例是

Accept-Charset: iso-8859-5, unicode-1-1;q=0.8

特殊值“*”如果出现在 Accept-Charset 头字段中,则匹配 字段其他位置未提及的每个字符集。

12.5.3. Accept-Encoding

“Accept-Encoding”头字段可用于指示对 内容编码使用的偏好(第 8.4.1 节)。

当由用户代理在请求中发送时,Accept-Encoding 指示响应中 可接受的内容编码。

当由服务器在响应中发送时,Accept-Encoding 提供有关 对同一资源后续请求的内容中首选哪些 内容编码的信息。

“identity”令牌用作“无编码”的同义词,以便传达 不首选任何编码的情况。

  Accept-Encoding  = #( codings [ weight ] )
  codings          = content-coding / "identity" / "*"

每个 codings 值都可以给出一个关联的质量值 (权重),表示对该编码的偏好,如 第 12.4.2 节所定义。Accept-Encoding 字段中的星号 “*”符号匹配字段中未 明确列出的任何可用内容编码。

示例:

Accept-Encoding: compress, gzip
Accept-Encoding:
Accept-Encoding: *
Accept-Encoding: compress;q=0.5, gzip;q=1.0
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0

服务器使用以下规则测试给定表示的内容编码是否可接受:

  1. 如果请求中没有 Accept-Encoding 头字段,则任何内容编码都被 用户代理视为可接受。
  2. 如果表示没有内容编码,则默认可接受, 除非 Accept-Encoding 头字段明确排除它,即声明 “identity;q=0”或“*;q=0”,且没有更具体的“identity”条目。
  3. 如果表示的内容编码是 Accept-Encoding 字段值中列出的内容编码之一, 则它是可接受的,除非伴随 qvalue 为 0。(如 第 12.4.2 节所定义,qvalue 为 0 表示“不可 接受”。)

表示可以使用多个内容编码。但是,大多数 内容编码是实现相同目的的替代方式(例如数据 压缩)。在具有相同 目的的多个内容编码之间进行选择时,首选非零 qvalue 最高的可接受内容编码 。

字段值为空的 Accept-Encoding 头字段表示 用户代理不希望响应使用任何内容编码。如果请求中存在非空 Accept-Encoding 头字段,并且响应的所有可用 表示都没有被列为可接受的内容编码, 则除非 identity 编码被指示为不可接受,否则源服务器应该发送不带任何内容 编码的响应。

当 Accept-Encoding 头字段出现在响应中时,它指示 资源愿意在相关请求中接受哪些 内容编码。字段值的求值方式与请求中相同。

请注意,此信息特定于相关请求;同一服务器上其他资源 所支持的编码集合可能不同,并且 可能随时间变化或取决于请求的其他方面(例如 请求方法)。

由于不支持的内容编码而使请求失败的服务器应当以 415(不支持的媒体类型)状态响应, 并在该响应中包含 Accept-Encoding 头字段,使客户端能够 区分与内容编码和媒体类型有关的问题。为了 避免与媒体类型相关问题混淆,因为与内容编码无关的原因而以 415 状态使请求失败的服务器不得 包含 Accept-Encoding 头字段。

Accept-Encoding 最常见的用途是在客户端乐观使用内容编码后, 响应 415(不支持的媒体类型)状态码时使用 。但是,该头字段也可以 用于向客户端指示支持内容编码,以优化 未来交互。例如,当请求 内容足够大,值得使用压缩编码但客户端未这样做时,资源可以在 2xx(成功)响应中包含它。

12.5.4. Accept-Language

用户代理可以使用“Accept-Language”头字段指示响应中首选的 自然语言集合。语言标签定义于 第 8.5.1 节。

每个 language-range 都可以关联一个质量值,用来表示 对该范围所指定语言的用户偏好估计,如 第 12.4.2 节所定义。例如,

Accept-Language: da, en-gb;q=0.8, en;q=0.7

将表示:“我更喜欢丹麦语,但也接受英式英语和其他类型的 英语”。

请注意,某些接收方将语言标签列出的顺序视为 优先级递减的指示,尤其是分配了相同 质量值的标签(没有值等同于 q=1)。但是,不能 依赖这种行为。为了保持一致并最大化互操作性,许多用户代理 为每个语言标签分配唯一质量值,同时也按 质量递减顺序列出它们。有关语言优先级列表的更多讨论见 [RFC4647] 的第 2.3 节。

对于匹配,[RFC4647] 的第 3 节定义了若干 匹配方案。实现可以提供最适合 其要求的匹配方案。“基本过滤”方案([RFC4647],第 3.3.1 节)与先前在 HTTP 中由 [RFC2616] 的第 14.4 节定义的匹配方案相同。

在每个请求中发送包含用户完整语言偏好的 Accept-Language 头字段,可能违背用户的隐私预期 (第 17.13 节)。

由于可理解性高度依赖于具体用户,用户代理需要 允许用户控制语言偏好(通过配置 用户代理本身,或者默认采用用户可控制的系统设置)。不向用户提供此类控制的 用户代理不得 发送 Accept-Language 头字段。

12.5.5. Vary

响应中的“Vary”头字段描述请求消息中除方法和目标 URI 之外,哪些部分可能影响源服务器 选择此响应内容的过程。

  Vary = #( "*" / field-name )

Vary 字段值要么是通配符成员“*”,要么是请求字段 名称列表,这些名称称为选择头字段,它们可能在为此响应选择 表示时发挥作用。潜在的选择头字段并不 限于本规范定义的字段。

包含成员“*”的列表表示请求的其他方面可能在 选择响应表示时发挥作用,可能包括消息语法 之外的方面(例如客户端的网络地址)。如果不将请求转发到源服务器,接收方将 无法确定此响应是否适合后续请求 。代理不得 在 Vary 字段值中生成“*”。

例如,包含以下内容的响应

Vary: accept-encoding, accept-language

表示源服务器可能使用了请求的 Accept-Encoding 和 Accept-Language 头字段(或 缺少这些字段)作为选择此响应内容时的决定因素 。

包含字段名称列表的 Vary 字段有两个目的:

  1. 告知缓存接收方,除非后续请求的 所列头字段值与原始请求相同( [CACHING] 的第 4.1 节),或者响应的复用已由源服务器验证,否则它们不得使用 此响应满足后续请求。换言之,Vary 扩展了将新请求与已存储 缓存条目匹配所需的缓存键。

  2. 告知用户代理接收方,此响应经过了内容 协商(第 12 节),并且如果所列头字段提供其他值, 后续请求中可能发送不同的 表示(主动协商)。

当源服务器希望可缓存响应仅选择性地复用于 后续请求时,应该为该响应生成 Vary 头字段 。通常,当响应内容根据这些选择头字段表达的偏好进行定制以更好地匹配时, 就属于这种情况, 例如源服务器根据请求的 Accept-Language 头 字段选择响应语言时。

当源服务器认为内容选择中的变化不如 Vary 对缓存性能的影响重要时, 可以省略 Vary,尤其是在 复用已经受到缓存响应指令限制时([CACHING] 的第 5.2 节)。

无需在 Vary 中发送 Authorization 字段名称,因为 字段定义已经禁止将该响应复用于不同用户(第 11.6.2 节)。同样,如果响应内容 根据网络区域选择或受其影响,但源服务器希望即使接收方从一个区域移动到另一个区域, 缓存响应仍可复用, 则源服务器无需在 Vary 中指示这种变化。

13. 条件请求

条件请求是带有一个或多个请求头字段的 HTTP 请求,这些字段指示 在将请求方法应用于目标资源之前要测试的前置条件。第 13.2 节定义何时 对前置条件求值,以及存在多个前置条件时它们的优先顺序 。

条件 GET 请求是 HTTP 缓存更新最高效的机制 [CACHING]。条件也可以应用于 状态更改方法,例如 PUT 和 DELETE,以防止“更新丢失”问题:一个 客户端意外覆盖另一个并行操作客户端的工作。

13.1. 前置条件

前置条件通常针对目标资源整体的某个状态 (其当前值集合)或先前获得的 表示中观察到的状态(该集合中的一个值)定义。如果资源具有多个当前 表示,每个表示都有自己的可观察状态,则前置条件会假定 每个请求到选定 表示(第 3.2 节)的映射随时间保持一致。无论如何,如果映射不一致或 服务器无法选择适当的表示,那么当前置条件求值为 false 时也不会造成损害 。

下面定义的每个前置条件都包括将从目标资源先前表示 获得的一组验证器,与选定表示的当前 验证器状态进行比较(第 8.8 节)。因此,这些前置条件求值 目标资源的状态自客户端已知的某个给定状态以来是否已经改变 。这种求值的效果取决于方法语义和条件的选择, 如 第 13.2 节中所定义。

由其他规范定义为扩展字段的其他前置条件,可以对 所有接收方、目标资源的一般状态或 一组资源施加条件。例如,如果接收方理解并实现 WebDAV 中的“If”头字段, 该字段可以使请求 取决于多个资源的各种方面,例如锁([WEBDAV], 第 10.4 节)。

只有当前置条件在未知时可以被安全 忽略(例如 If-Modified-Since)、可以假定针对给定用例已部署, 或者目标资源的某个其他属性表明已实现时,前置条件的可扩展性才可能实现 。这鼓励将重点放在共同商定部署的通用标准上。

13.1.1. If-Match

“If-Match”头字段使请求方法取决于接收方 源服务器在字段值为“*”时至少具有目标 资源的一个当前表示,或者具有目标资源的当前表示, 且该表示的实体标签与字段值中提供的实体标签列表中的某个成员 匹配。

源服务器在比较 If-Match 的实体标签时必须使用强比较函数 (第 8.8.3.2 节),因为客户端希望此 前置条件在表示数据发生任何变化时阻止方法被应用 。

  If-Match = "*" / #entity-tag

示例:

If-Match: "xyzzy"
If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-Match: *

If-Match 最常与状态更改方法(例如 POST、PUT、DELETE)一起使用,以 防止多个用户代理可能并行 操作同一资源时意外覆盖(即防止“更新丢失”问题)。通常,它 可以与任何涉及选择或修改 表示的方法一起使用,当选定表示的当前实体标签不是 If-Match 字段值中的成员时中止请求。

当源服务器收到选择表示且 包含 If-Match 头字段的请求时,源服务器在 执行方法之前必须按照 第 13.2 节对 If-Match 条件求值。

要对收到的 If-Match 头字段求值:

  1. 如果字段值为“*”,且源服务器具有 目标资源的当前表示,则条件为 true。
  2. 如果字段值为实体标签列表,并且列出的标签中任何一个 与选定表示的实体标签匹配,则条件为 true。
  3. 否则,条件为 false。

对 If-Match 条件求值的源服务器在条件求值为 false 时不得 执行所请求的方法。相反, 源服务器可以通过以 412(前置条件 失败)状态码响应,指示条件请求 失败。或者,如果请求是看起来已经应用于选定表示的状态更改 操作, 源服务器可以以 2xx(成功)状态码响应(即用户代理请求的更改 已经成功,但用户代理可能并不知道, 可能因为先前响应丢失,或其他 用户代理执行了等效更改)。

当更改请求看起来已经应用时,允许源服务器发送成功响应 对许多创作用例更高效,但如果多个用户代理正在发出非常 相似但不协作的更改请求,也存在一些风险。例如,多个用户代理写入一个公共 资源作为信号量(例如非原子递增),很可能会发生冲突并 可能丢失重要状态转换。对于这类资源, 源服务器最好严格地对不安全方法中每个失败的 前置条件发送 412。在其他情况下,从成功响应中排除 ETag 字段 可以促使用户代理将 GET 作为其下一个请求 ,以消除对资源当前状态的混淆。

客户端可以在 GET 请求中发送 If-Match 头字段,以表示 如果选定表示不匹配,它更希望收到 412(前置条件失败)响应 。但是,这仅在范围 请求(第 14 节)中用于 在不希望获得新表示时完成先前收到的部分表示才有用 。当客户端更希望 收到新表示时,If-Range(第 13.1.5 节)更适合范围请求。

缓存或中间方可以忽略 If-Match,因为其 互操作特性仅对源服务器有必要。

请注意,列表值包含“*”和其他值 (包括其他“*”实例)的 If-Match 头字段在语法上无效(因此不允许 生成),而且很可能无法互操作。

13.1.2. If-None-Match

“If-None-Match”头字段使请求方法取决于接收方 缓存或源服务器在字段值为“*”时没有目标 资源的任何当前表示,或者具有一个选定表示,其 实体标签与字段值中列出的任何实体标签均不匹配。

接收方在比较 If-None-Match 的实体标签时必须使用弱比较函数 (第 8.8.3.2 节),因为即使表示数据发生变化, 弱实体标签仍可用于 缓存验证。

示例:

If-None-Match: "xyzzy"
If-None-Match: W/"xyzzy"
If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"
If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"
If-None-Match: *

If-None-Match 主要用于条件 GET 请求,以最小的事务开销 高效更新缓存信息。当 客户端希望更新一个或多个具有实体标签的已存储响应时, 客户端在发出 GET 请求时应该生成包含这些实体标签列表的 If-None-Match 头字段 ;这允许 接收服务器在这些已存储响应中的某个与 选定表示匹配时发送 304(未 修改)响应。

If-None-Match 也可以使用“*”值,以防止不安全的请求 方法(例如 PUT)在客户端认为资源没有当前表示时, 无意中修改目标资源的现有表示 (第 9.2.1 节)。 这是“更新丢失”问题的一种变体,当多个 客户端尝试为目标资源创建初始表示时可能发生。

当源服务器收到选择表示且 包含 If-None-Match 头字段的请求时,源服务器在 执行方法之前必须按照 第 13.2 节对 If-None-Match 条件求值。

要对收到的 If-None-Match 头字段求值:

  1. 如果字段值为“*”,且源服务器具有 目标资源的当前表示,则条件为 false。
  2. 如果字段值为实体标签列表,并且列出的标签之一 与选定表示的实体标签匹配,则条件为 false。
  3. 否则,条件为 true。

对 If-None-Match 条件求值的源服务器在条件求值为 false 时不得 执行所请求的方法; 相反,源服务器必须响应以下之一:a) 如果 请求方法是 GET 或 HEAD,则响应 304(未修改)状态码;或 b) 对所有其他请求方法响应 412 (前置条件失败)状态码。

缓存处理收到的 If-None-Match 头字段的要求定义 于 [CACHING] 的第 4.3.2 节。

请注意,列表值包含“*”和其他 值(包括其他“*”实例)的 If-None-Match 头字段在语法上无效(因此不 允许生成),而且很可能无法互操作。

13.1.3. If-Modified-Since

“If-Modified-Since”头字段使 GET 或 HEAD 请求方法取决于 选定表示的 修改日期是否晚于字段值中提供的日期。 如果该数据未发生变化,则避免传输选定表示的数据 。

该字段的一个示例是:

If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

如果请求包含 If-None-Match 头 字段,接收方必须忽略 If-Modified-Since;If-None-Match 中的条件被视为 If-Modified-Since 条件更准确的替代,而二者组合仅是为了 与可能未实现 If-None-Match 的旧中间方互操作。

如果收到的字段值不是有效的 HTTP-date、字段值具有多个 成员,或者请求方法既不是 GET 也不是 HEAD, 接收方必须忽略 If-Modified-Since 头字段。

如果资源没有可用的修改日期,接收方必须忽略 If-Modified-Since 头字段 。

接收方必须按照源服务器的时钟解释 If-Modified-Since 字段值的 时间戳。

If-Modified-Since 通常用于两个不同目的:1) 高效 更新没有实体标签的缓存表示,以及 2) 将 Web 遍历范围限制为最近发生变化的资源。

用于缓存更新时,缓存通常会使用缓存 消息的 Last-Modified 头字段值 生成 If-Modified-Since 的字段值。对于时钟同步不良,或者服务器选择只接受精确时间戳匹配的情况, 这种行为具有最佳互操作性(因为当源服务器时钟被校正 或表示从存档备份恢复时,Last-Modified 日期可能看起来“倒退”)。但是,缓存 有时会基于其他数据生成字段值,例如缓存消息的 Date 头字段,或 消息收到时的时钟时间,特别是在缓存 消息不包含 Last-Modified 头字段时。

用于将检索范围限制在近期时间窗口时,用户代理 会基于自己的时钟或先前响应中从服务器收到的 Date 头字段生成 If-Modified-Since 字段值 。基于选定表示的 Last-Modified 头字段选择精确时间戳匹配的源服务器 无法帮助用户 代理将其数据传输限制为仅包含指定窗口内发生变化的内容。

当源服务器收到选择表示且 包含 If-Modified-Since 头字段、但不包含 If-None-Match 头字段的请求时, 源服务器在 执行方法之前应该按照 第 13.2 节对 If-Modified-Since 条件求值。

要对收到的 If-Modified-Since 头字段求值:

  1. 如果选定表示的最后修改日期早于或等于 字段值中提供的日期,则条件为 false。
  2. 否则,条件为 true。

对 If-Modified-Since 条件求值的源服务器在条件求值为 false 时不应该执行所请求的方法;相反,源服务器应该 生成 304(未修改)响应, 仅包含对标识或更新 先前缓存响应有用的元数据。

缓存处理收到的 If-Modified-Since 头字段的要求定义 于 [CACHING] 的第 4.3.2 节。

13.1.4. If-Unmodified-Since

“If-Unmodified-Since”头字段使请求方法取决于选定表示的最后 修改日期是否早于或等于字段 值中提供的日期。当用户代理没有表示的实体 标签时,此字段实现与 If-Match 相同的目的。

该字段的一个示例是:

If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT

如果请求包含 If-Match 头字段, 接收方必须忽略 If-Unmodified-Since;If-Match 中的 条件被视为 If-Unmodified-Since 条件更准确的替代,而二者 组合仅是为了与可能未实现 If-Match 的旧中间方互操作。

如果收到的字段值不是有效的 HTTP-date(包括字段值 看起来像日期列表的情况),接收方必须忽略 If-Unmodified-Since 头字段 。

如果资源没有可用的修改日期,接收方必须忽略 If-Unmodified-Since 头字段 。

接收方必须按照源服务器的时钟解释 If-Unmodified-Since 字段 值的时间戳。

If-Unmodified-Since 最常与状态更改方法(例如 POST、PUT、 DELETE)一起使用,以防止多个用户代理并行操作 不随表示提供实体标签的资源时发生意外覆盖 (即防止“更新丢失”问题)。通常,它可以与任何 涉及选择或修改表示的方法一起使用,如果选定 表示的最后修改日期自 If-Unmodified-Since 字段值中提供的日期以来发生变化,则中止 请求。

当源服务器收到选择表示且 包含 If-Unmodified-Since 头字段、但不包含 If-Match 头字段的请求时,源服务器 在 执行方法之前必须按照 第 13.2 节对 If-Unmodified-Since 条件求值。

要对收到的 If-Unmodified-Since 头字段求值:

  1. 如果选定表示的最后修改日期早于或等于 字段值中提供的日期,则条件为 true。
  2. 否则,条件为 false。

对 If-Unmodified-Since 条件求值的源服务器在条件 求值为 false 时不得执行所请求的方法。相反,源服务器可以通过以 412(前置条件失败)状态码响应,指示 条件请求失败。或者,如果 请求是看起来已经应用于 选定表示的状态更改操作,则源服务器可以以 2xx(成功)状态码响应(即 用户代理请求的更改已经成功,但用户代理 可能并不知道,或许因为先前响应丢失,或 其他用户代理执行了等效更改)。

当更改请求看起来 已经应用时,允许源服务器发送成功响应对许多创作用例更高效,但如果多个用户代理正在发出非常 相似但不协作的更改请求,则存在一些风险。在这些情况下,源服务器最好 严格地对不安全方法中每个失败的前置条件发送 412。

客户端可以在 GET 请求中发送 If-Unmodified-Since 头字段,以指示 如果选定表示已被修改,它更希望收到 412(前置条件失败) 响应。但是,这仅 在范围请求(第 14 节)中用于完成先前收到的部分表示、且 不希望获得新表示时才有用。当客户端更希望收到新表示时,If-Range(第 13.1.5 节)更 适合范围请求。

缓存或中间方可以忽略 If-Unmodified-Since,因为 其互操作特性仅对源服务器有必要。

13.1.5. If-Range

“If-Range”头字段提供一种特殊条件请求机制, 类似于 If-Match 和 If-Unmodified-Since 头 字段,但它指示接收方在验证器不匹配时忽略 Range 头字段,从而 传输新的选定 表示,而不是返回 412 (前置条件失败)响应。

如果客户端具有某个表示的部分副本,并希望获得整个表示的最新 副本,则可以将 Range 头字段与条件 GET 一起使用(使用 If-Unmodified-Since 和 If-Match 中任一或两者)。但是,如果前置条件 因表示已被修改而失败,则客户端随后必须 发出第二个请求来获取整个当前表示。

“If-Range”头字段允许客户端“短路”第二个请求。 非正式地说,其含义如下:如果表示未改变,就发送我在 Range 中请求的部分;否则,发送整个 表示。

可以通过检查前三个 字符中是否存在 DQUOTE,将有效的 entity-tag 与有效的 HTTP-date 区分开来。

客户端不得在不包含 Range 头 字段的请求中生成 If-Range 头字段。服务器收到 不包含 Range 头字段的请求中的 If-Range 头字段时必须忽略它。源服务器收到针对不支持 Range 请求的目标资源的 If-Range 头字段时必须忽略它。

客户端不得生成包含标记为弱的 实体标签的 If-Range 头字段。除非客户端没有相应表示的实体标签, 且日期是 第 8.8.2.2 节定义意义上的强验证器, 否则客户端不得 生成包含 HTTP-date 的 If-Range 头字段。

收到 Range 请求上的 If-Range 头字段的服务器在执行 方法之前必须按照 第 13.2 节对条件求值。

要对包含 HTTP-date 的收到的 If-Range 头字段求值:

  1. 如果提供的 HTTP-date 验证器不是 第 8.8.2.2 节定义意义上的强验证器,则条件为 false。
  2. 如果提供的 HTTP-date 验证器 与选定表示的 Last-Modified 字段值完全匹配, 则条件为 true。
  3. 否则,条件为 false。

要对包含 entity-tag 的收到的 If-Range 头字段求值:

  1. 如果提供的 entity-tag 验证器 使用强比较函数(第 8.8.3.2 节)与 选定表示的 ETag 字段值完全匹配,则 条件为 true。
  2. 否则,条件为 false。

If-Range 头字段的接收方在 If-Range 条件求值为 false 时必须忽略 Range 头字段。否则,接收方应该 按请求处理 Range 头字段。

请注意,If-Range 比较采用精确匹配,包括验证器为 HTTP-date 时,因此它不同于 对 If-Unmodified-Since 条件求值时使用的“早于或等于”比较。

13.2. 前置条件的求值

13.2.1. 何时求值

除下文排除的情况外,接收方缓存或源服务器在 成功执行其正常请求检查后,并且就在其将处理 请求内容(如果有)或执行与请求 方法相关的操作之前,必须对收到的请求前置条件求值。如果在处理 请求内容之前,对不带这些条件的同一请求的响应本应是 2xx(成功)或 412 (前置条件失败)以外的状态码,则服务器必须忽略所有收到的前置条件。换言之, 在进行大量处理之前能够检测到的重定向和失败优先于 前置条件的求值。

如果服务器不是目标资源的源服务器,并且不能作为 目标资源请求的缓存,则它不得对 本规范定义的条件请求头字段求值,并且如果请求被转发,它必须转发这些字段,因为生成这些字段的客户端希望 由能够提供当前表示的服务器对其求值 。同样,当本规范定义的条件请求头字段 与不涉及选择或修改选定表示的请求方法一起收到时, 例如 CONNECT、OPTIONS 或 TRACE,服务器必须忽略这些字段。

请注意,协议扩展可以修改前置条件 求值的条件或求值结果。例如,immutable 缓存 指令(由 [RFC8246]定义)指示缓存 在持有新鲜响应时放弃转发条件请求。

虽然条件请求头字段被定义为可与 HEAD 方法一起使用(以保持 HEAD 的语义与 GET 一致),但发送条件 HEAD 没有意义, 因为成功响应的大小与 304(未修改)响应大致相同,而且比 412(前置条件失败)响应更有用 。

13.2.2. 前置条件的优先级

当一个请求中存在多个条件请求头字段时, 字段求值的顺序变得重要。实际中,本文 定义的字段始终按单一逻辑顺序实现, 因为“更新丢失”前置条件比缓存 验证具有更严格的要求,经过验证的缓存比部分响应更高效,而实体 标签被认为比日期验证器更准确。

接收方缓存或源服务器必须按照以下顺序对本规范定义的请求 前置条件求值:

  1. 当接收方是源服务器且存在 If-Match 时,对 If-Match 前置条件求值:

  2. 当接收方是源服务器、If-Match 不存在,并且 If-Unmodified-Since 存在时,对 If-Unmodified-Since 前置条件求值:

  3. 当存在 If-None-Match 时, 对 If-None-Match 前置条件求值:

  4. 当方法是 GET 或 HEAD、If-None-Match 不存在,并且 If-Modified-Since 存在时,对 If-Modified-Since 前置条件求值:

  5. 当方法是 GET,且 Range 和 If-Range 都存在时,对 If-Range 前置条件求值:

  6. 否则,

    • 执行所请求的方法,并根据其成功或 失败进行响应。

任何定义附加条件请求头字段的 HTTP 扩展都应当 定义这些字段相对于本文定义字段以及实际中可能存在的其他条件字段 的求值顺序。

14. 范围 请求

客户端经常会遇到因请求被取消或连接 中断而导致的数据传输中断。当客户端已经存储了部分表示时,最好 在后续请求中请求该表示的其余部分,而不是传输 整个表示。同样,本地存储空间有限的设备可能会受益于 只请求较大表示的一个子集,例如一个非常 大的文档中的单个页面,或嵌入图像的尺寸。

范围请求是 HTTP 的一个可选特性,其设计使得 未实现此特性(或不支持目标资源使用此特性)的接收方能够 像处理普通 GET 请求一样响应,而不影响互操作性。部分 响应通过不同的状态码来指示,以免未实现该特性的缓存将其误认为完整响应 。

14.1. 范围单位

当表示数据的内容编码或媒体类型中存在可寻址的 固有结构单位时,可以将表示数据划分为子范围。例如, 八位字节(又称字节)边界是所有表示数据共有的结构单位, 允许将数据分区标识为相对于 该数据开头或末尾某个偏移量的一段字节范围。

范围单位这一通用概念用于 Accept-Ranges(第 14.3 节)响应头字段中,以宣告 对范围请求的支持;用于 Range(第 14.2 节) 请求头字段中,以界定所请求的表示部分;以及 用于 Content-Range(第 14.4 节)头字段中,以描述正在传输表示的哪一部分。

所有范围单位名称均不区分大小写,并且应当注册到“HTTP 范围单位注册表”中,如 第 16.5.1 节所定义。

范围单位旨在可扩展,如 第 16.5 节所述。

14.1.1. 范围说明符

范围使用范围单位与一组范围说明符配对来表示。 范围单位名称决定哪些类型的 range-spec 可用于其自身的 说明符。因此,下面的语法是通用的:每个范围单位都应当 指定何时允许 int-range、 suffix-range 和 other-range 的要求。

范围请求可以指定单个范围或单个表示中的一组 范围。

int-range 是一个 使用两个非负整数表示的范围,或者使用一个非负整数表示从该位置一直到 表示数据末尾的范围。范围单位指定这些整数 的含义(例如,它们可能表示从开头开始的单位偏移量、包含端点的编号 部分等)。

如果存在 last-pos 值,并且它小于 first-pos,则 int-range 无效。

suffix-range 是一个以表示数据后缀表示的范围,其最大长度为所提供的 非负整数(以范围单位计)。换言之,即表示数据最后 N 个 单位。

为了提供可扩展性,other-range 规则是一种基本不受约束的语法,允许 特定于应用程序或未来的范围单位定义附加范围说明符。

  other-range   = 1*( %x21-2B / %x2D-7E )
                ; 1*(VCHAR,不包括逗号)

如果 ranges-specifier 包含对所指示 range-unit 无效或未定义的任何 range-spec, 则该 ranges-specifier 无效。

如果有效的 ranges-specifier 至少包含一个按照所指示 range-unit 定义为可满足的 range-spec, 则它是可满足的。否则,ranges-specifier 是不可满足的。

14.1.2. 字节范围

“bytes”范围单位用于表示表示数据八位字节 序列的子范围。每个字节范围表示为相对于 表示数据开头(int-range)或 末尾(suffix-range)某个偏移量的整数范围 。字节范围不使用 other-range 说明符。

bytes int-range 中的 first-pos 值给出范围中第一个 字节的偏移量。last-pos 值给出 范围中最后一个字节的偏移量;也就是说,指定的字节位置 包含端点。字节偏移量从零开始。

如果表示数据应用了内容编码,则每个字节范围 都相对于编码后的字节序列进行计算,而不是相对于 解码后获得的底层字节序列。

bytes 范围说明符的示例:

  • 前 500 个字节(字节偏移量 0-499,包含端点):

    bytes=0-499
    
  • 第二个 500 字节(字节偏移量 500-999,包含端点):

    bytes=500-999
    

客户端可以在不知道选定表示大小的情况下限制所请求的字节数。如果 last-pos 值不存在,或者该值 大于或等于表示数据的当前长度,则字节 范围被解释为表示的剩余部分(即服务器 将 last-pos 的值替换为 比选定表示当前长度小一的值)。

客户端可以使用 suffix-range 引用选定表示的最后 N 个字节(N > 0) 。如果选定 表示短于指定的 suffix-length,则使用整个表示。

其他示例,假定表示长度为 10000:

  • 最后 500 个字节(字节偏移量 9500-9999,包含端点):

    bytes=-500
    

    或者:

    bytes=9500-
    
  • 仅第一个和最后一个字节(字节 0 和 9999):

    bytes=0-0,-1
    
  • 开头、中间和末尾各 1000 个字节:

    bytes= 0-999, 4500-5499, -1000
    
  • 第二个 500 字节的其他有效(但非规范)说明 (字节偏移量 500-999,包含端点):

    bytes=500-600,601-999
    bytes=500-700,601-999
    

对于 GET 请求,有效的 bytes range-spec 在满足以下任一条件时是可满足的:

当选定表示的长度为零时,GET 请求中的 range-spec 唯一可满足的形式是一个 suffix-range,其 suffix-length 非零。

在字节范围语法中,first-pos、last-pos 和 suffix-length 以 八位字节的十进制数表示。由于内容长度没有预定义限制, 接收方必须预期可能出现很大的十进制 数字,并防止整数转换溢出导致解析错误。

14.2. Range

GET 请求中的“Range”头字段修改方法语义,以请求 仅传输选定表示数据(第 8.1 节)的一个或多个子范围,而不是整个选定 表示。

服务器可以忽略 Range 头字段。但是,源 服务器和中间缓存应当在可能时支持字节范围,因为它们 支持从部分失败的传输中高效恢复,以及部分检索 大型表示。

如果收到 Range 头字段时所用请求 方法无法识别,或没有为该方法定义范围处理,则服务器必须忽略该字段。对于本 规范,GET 是唯一 定义了范围处理的方法。

源服务器必须忽略包含其 不理解范围单位的 Range 头字段。代理可以丢弃包含其不理解范围单位的 Range 头字段。

支持范围请求的服务器可以忽略或拒绝包含无效 ranges-specifier(第 14.1.1 节)、包含两个以上 重叠范围的 ranges-specifier,或者包含许多未按升序列出的小范围集合的 Range 头字段,因为这些迹象表明客户端存在缺陷,或存在蓄意的 拒绝服务攻击(第 17.15 节)。客户端不应该请求多个本质上比包含相同数据的单个范围处理和传输效率更低的范围 。

当选定表示没有内容(即选定表示的数据长度为零)时, 支持范围请求的服务器可以忽略 Range 头字段。

请求多个范围的客户端应该按升序列出这些 范围(它们在完整表示中通常被接收的顺序), 除非有特定需要先请求后面的部分。例如,处理具有内部 部分目录的大型表示的用户代理可能需要先请求后面的部分, 特别是当表示由逆序存储的页面组成,而用户代理希望 一次传输一页时。

Range 头字段在对 第 13.1 节定义的前置条件头字段求值后进行求值,并且仅当 没有 Range 头字段时结果会是 200 (OK) 响应时才如此。换言之,当 条件 GET 会产生 304(未 修改)响应时,Range 会被忽略。

If-Range 头字段(第 13.1.5 节)可用作应用 Range 头字段的前置条件。

如果所有前置条件均为 true,服务器支持目标资源的 Range 头字段, 收到的 Range 字段值包含有效的 ranges-specifier,且其中的 range-unit 受该目标资源支持, 并且该 ranges-specifier 相对于选定 表示是可满足的,则服务器应该发送 206(部分内容)响应,其内容包含与所请求的可满足 range-spec 对应的一个或多个 部分表示。

上述内容并不意味着服务器会发送所有请求的范围。在某些情况下, 可能只能(或更高效地)先发送请求范围的一部分, 并期望客户端稍后在仍需要剩余部分时重新请求 (参见 第 15.3.7 节)。

如果所有前置条件均为 true,服务器支持目标资源的 Range 头字段, 收到的 Range 字段值包含有效的 ranges-specifier,并且 range-unit 不受该目标 资源支持,或者 ranges-specifier 相对于选定表示不可满足,则服务器应该发送 416(范围不可 满足)响应。

14.3. Accept-Ranges

响应中的“Accept-Ranges”字段指示上游服务器是否支持 目标资源的范围请求。

例如,支持字节范围请求(第 14.1.2 节)的服务器可以发送字段

Accept-Ranges: bytes

以指示它支持该目标资源的字节范围请求,从而 鼓励客户端将其用于同一请求路径上的未来部分请求。 范围单位定义于 第 14.1 节。

无论是否收到 Accept-Ranges 字段,客户端都可以生成范围请求 。该信息只是为了提高 性能并减少不必要的网络传输而提供的建议。

相反,客户端不得假定收到 Accept-Ranges 字段就意味着未来的范围请求会返回部分响应。 内容可能发生变化,服务器可能仅在特定时间或 特定条件下支持范围请求,或者下一个请求可能由不同的中间方处理 。

不支持目标资源任何类型范围请求的服务器可以发送

Accept-Ranges: none

以建议客户端不要在同一请求路径上尝试范围请求。范围 单位“none”为此目的保留。

Accept-Ranges 字段可以在尾部部分中发送,但 最好作为头字段发送,因为该信息对于 重新启动在内容传输中途失败的大型信息传输特别有用(在 收到尾部部分之前)。

14.4. Content-Range

“Content-Range”头字段在单部分 206(部分内容)响应中发送,以指示作为消息内容所包含的选定表示的部分范围 ;在多部分 206 响应的每个部分中发送,以指示 每个主体部分中包含的范围(第 14.6 节);并在 416(范围不可满足)响应中发送,以提供 有关选定表示的信息。

如果 206(部分内容)响应包含一个 Content-Range 头字段,其中的 范围单位(第 14.1 节)是接收方不理解的,则 接收方不得尝试将其与已存储的 表示重新组合。收到此类消息的代理应该 将其向下游转发。

Content-Range 也可以作为请求修饰符发送,以根据 客户端与源服务器之间的私有协议请求部分 PUT,如 第 14.5 节所述。服务器必须忽略在没有定义 Content-Range 支持的方法请求中收到的 Content-Range 头字段 。

对于字节范围,发送方应该指示从中提取范围的 表示的完整长度,除非完整长度 未知或难以确定。使用星号字符(“*”)代替 complete-length 表示生成头 字段时表示长度未知。

下面的示例说明发送方已知选定表示的完整长度 为 1234 字节时的情况:

Content-Range: bytes 42-1233/1234

第二个示例说明完整长度未知时的情况:

Content-Range: bytes 42-1233/*

如果 Content-Range 字段值包含的 range-resp 具有小于其 first-pos 值的 last-pos 值,或者 complete-length 值小于或等于其 last-pos 值,则该字段值无效。无效 Content-Range 的接收方不得 尝试将收到的内容与已存储的表示重新组合。

生成针对字节范围请求的 416(范围不可满足) 响应的服务器应该发送带有 unsatisfied-range 值的 Content-Range 头字段,如以下示例:

Content-Range: bytes */1234

416 响应中的 complete-length 指示选定 表示的当前长度。

对于未明确 描述其语义的状态码,Content-Range 头字段没有意义。对于本规范,只有 206(部分内容)和 416 (范围不可满足)状态码描述了 Content-Range 的含义。

以下是 Content-Range 值的示例,其中选定表示 总共包含 1234 个字节:

  • 前 500 个字节:

    Content-Range: bytes 0-499/1234
    
  • 第二个 500 字节:

    Content-Range: bytes 500-999/1234
    
  • 除前 500 个字节之外的所有字节:

    Content-Range: bytes 500-1233/1234
    
  • 最后 500 个字节:

    Content-Range: bytes 734-1233/1234
    

14.5. 部分 PUT

当用户代理在请求中发送 Content-Range 头字段(第 14.4 节)时,某些源服务器支持对部分表示执行 PUT ,尽管这种支持并不一致,并且依赖于与用户代理的私有 协议。一般而言,它请求使用所包含的内容部分替换目标资源的状态,替换位置和长度由 Content-Range 值指示,其中偏移量相对于 当前选定表示。

如果源服务器在不支持部分 PUT 请求的目标 资源的 PUT 中收到 Content-Range,则应该以 400(错误请求)状态码响应。

部分 PUT 与 PUT 的原始定义不向后兼容。它可能 导致内容被写入为当前 表示的完整替代。

还可以通过以单独标识的资源为目标来进行部分资源更新, 该资源的状态与较大资源的一部分重叠或扩展该部分,或者使用 专门为部分更新定义的其他方法(例如 [RFC5789]中定义的 PATCH 方法)。

14.6. 媒体类型 multipart/byteranges

当 206(部分内容)响应消息 包含多个范围的内容时,它们作为多部分消息主体中的主体部分传输 ([RFC2046], 第 5.1 节),其 媒体类型为“multipart/byteranges”。

“multipart/byteranges”媒体类型包含一个或多个主体部分,每个部分都有自己的 Content-Type 和 Content-Range 字段。必需的 boundary 参数指定用于分隔每个主体部分的边界字符串。

实现说明:

  1. 主体中的第一个边界字符串之前可能有额外的 CRLF。
  2. 尽管 [RFC2046] 允许 boundary 字符串带引号,但某些现有实现会错误处理 带引号的 boundary 字符串。
  3. 许多客户端和服务器是按照 byteranges 规范的早期草案编写的,该草案使用“multipart/x-byteranges”媒体类型,它与此类型几乎(但 并不完全)兼容。

尽管名称如此,“multipart/byteranges”媒体类型并不限于字节范围。 以下示例使用“exampleunit”范围单位:

HTTP/1.1 206 Partial Content
Date: Tue, 14 Nov 1995 06:25:24 GMT
Last-Modified: Tue, 14 July 04:58:08 GMT
Content-Length: 2331785
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: video/example
Content-Range: exampleunit 1.2-4.3/25

...第一个范围...
--THIS_STRING_SEPARATES
Content-Type: video/example
Content-Range: exampleunit 11.2-14.3/25

...第二个范围
--THIS_STRING_SEPARATES--

以下信息作为“multipart/byteranges” 媒体类型的注册表单。

类型名称:
multipart
子类型名称:
byteranges
必需参数:
boundary
可选参数:
不适用
编码考虑:
仅允许“7bit”、“8bit”或“binary”
安全考虑:
参见 第 17 节
互操作性考虑:
不适用
已发布的规范:
RFC 9110(参见 第 14.6 节)
使用此媒体类型的应用:
支持在单个请求中使用多个范围的 HTTP 组件
片段标识符考虑:
不适用
附加信息:
此类型已弃用的别名:
不适用
魔数:
不适用
文件扩展名:
不适用
Macintosh 文件类型代码:
不适用
用于联系以获取更多信息的人员和电子邮件地址:
参见作者地址章节。
预期用途:
COMMON
使用限制:
不适用
作者:
参见作者地址章节。
变更控制者:
IESG

15. 状态 码

响应的状态码是一个三位整数代码,用于描述 请求的结果和响应的语义,包括请求是否成功以及 包含什么内容(如果有)。所有有效状态码都在 100 到 599(含)的范围内。

状态码的第一位数字定义响应类别。后两位数字没有 任何分类作用。第一位数字有五种值:

HTTP 状态码是可扩展的。客户端不需要理解所有 已注册状态码的含义,尽管显然最好能够理解。但是,客户端 必须理解由 第一位数字指示的任何状态码类别,并将无法识别的状态码视为等同于该类别的 x00 状态 码。

例如,如果客户端收到无法识别的状态码 471,它可以从 第一位数字看出其请求存在某种问题,并将该响应视为 收到了 400(错误请求)状态码。该 响应消息通常会包含解释该状态的表示。

100..599 范围之外的值无效。实现通常使用该范围之外的三位整数 值(即 600..999)在内部传达非 HTTP 状态 (例如库错误)。收到包含无效状态码响应的客户端应该像收到 5xx(服务器错误)状态码一样处理该响应。

单个请求可以有多个关联响应:零个 或多个状态码位于“信息性” (1xx)范围内的临时(非最终)响应,随后恰好有一个状态码位于其他范围之一的最终 响应。

15.1. 状态码概述

下面列出的状态码由本规范定义。此处列出的原因短语 仅为建议——它们可以被本地等效内容替换或完全 省略,而不会影响协议。

定义为可启发式缓存的状态码响应(例如本规范中的 200、203、 204、206、300、301、308、404、405、410、414 和 501)可以由 缓存在启发式过期机制下复用,除非方法 定义或显式缓存控制另有指示 [CACHING];其他所有状态码都不 可启发式缓存。

本规范范围之外还规定了其他用于 HTTP 的状态码。所有此类状态码都应当注册到“超文本传输 协议 (HTTP) 状态码注册表”中,如 第 16.2 节所述。

15.2. 信息性 1xx

1xx(信息性)类别的状态码指示一个临时响应,用于 在完成所请求的操作并发送最终响应之前传达连接状态或请求进度 。由于 HTTP/1.0 未定义任何 1xx 状态码, 服务器不得向 HTTP/1.0 客户端发送 1xx 响应。

1xx 响应以头部部分结束而终止;它不能包含内容 或尾部字段。

客户端必须能够解析在最终响应之前收到的一个或多个 1xx 响应 ,即使客户端并未预期这些响应。用户代理可以忽略意外的 1xx 响应。

代理必须转发 1xx 响应,除非该代理自身 请求生成该 1xx 响应。例如,如果代理在转发请求时添加“Expect: 100-continue”头字段,则无需转发相应的 100(继续)响应。

15.2.1. 100 继续

100(继续)状态码表示请求的初始部分已经 收到,并且尚未被服务器拒绝。服务器打算在 请求完全收到并处理后发送最终响应。

当请求包含一个 Expect 头 字段,并且该字段包含 100-continue 期望时,100 响应表示服务器希望接收 请求内容,如 第 10.1.1 节所述。客户端应当 继续发送请求并丢弃 100 响应。

如果请求未包含带有 100-continue 期望的 Expect 头字段,则客户端可以直接丢弃此临时响应。

15.2.2. 101 切换协议

101(切换协议)状态码表示服务器理解并 愿意遵从客户端通过 Upgrade 头字段(第 7.8 节)提出的请求, 更改此连接上使用的应用协议。服务器必须在响应中生成 Upgrade 头字段, 指示此响应之后将生效的协议。

假定服务器只会在切换协议有利时同意切换 。例如,切换到更新版本的 HTTP 可能比旧版本 有利,而在交付使用实时同步特性的资源时, 切换到实时同步协议可能有利。

15.3. 成功 2xx

2xx(成功)类别的状态码表示客户端的请求已 成功收到、理解并接受。

15.3.1. 200 OK

200 (OK) 状态码表示请求已成功。200 响应中发送的内容 取决于请求方法。对于本 规范定义的方法,内容的预期含义可概括为:

表 6
请求方法 响应内容是以下内容的表示:
GET 目标 资源
HEAD 目标 资源,与 GET 一样,但不传输表示 数据
POST 操作的状态或从操作获得的结果
PUT, DELETE 操作的状态
OPTIONS 目标资源的通信选项
TRACE 返回跟踪的服务器所收到的请求消息

除对 CONNECT 的响应外,200 响应预期包含消息 内容,除非消息分帧明确指示内容长度为零 。如果请求的某个方面表示成功时偏好没有内容, 源服务器应当改为发送 204 (无内容)响应。对于 CONNECT,没有内容,因为 成功结果是一条隧道,它在 200 响应的 头部部分之后立即开始。

200 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

在对 GET 或 HEAD 的 200 响应中,源服务器应该发送 选定表示的任何可用验证器字段(第 8.8 节), 最好同时发送强实体标签和 Last-Modified 日期。

在对状态更改方法的 200 响应中,响应中发送的任何验证器字段(第 8.8 节)都传达 成功应用请求语义后形成的新表示的当前验证器 。请注意,PUT 方法(第 9.3.4 节)具有可能阻止发送此类验证器的附加 要求。

15.3.2. 201 已创建

201(已创建)状态码表示请求已经完成,并导致 创建一个或多个新资源。请求创建的主要资源 由响应中的 Location 头字段标识,或者如果未收到 Location 头字段,则由 目标 URI 标识。

201 响应内容通常描述并链接到所创建的资源。 响应中发送的任何验证器字段(第 8.8 节)都传达请求所创建新 表示的当前验证器。请注意,PUT 方法(第 9.3.4 节)具有可能阻止发送此类验证器的附加要求。

15.3.3. 202 已接受

202(已接受)状态码表示请求已被接受以进行 处理,但处理尚未完成。该请求最终可能会被执行,也可能 不会被执行,因为实际处理时可能被禁止 。HTTP 没有用于从异步操作重新发送状态码的机制。

202 响应有意不作承诺。其目的是允许服务器 接受由其他某个过程处理的请求(可能是每天只运行一次的面向批处理的过程 ),而无需用户代理与 服务器的连接一直保持到该过程完成。与此 响应一起发送的表示应当描述请求的当前状态,并指向(或嵌入) 一个状态监视器,该监视器可以向用户提供请求何时 完成的估计。

15.3.4. 203 非权威信息

203(非权威信息)状态码表示请求已 成功,但所包含内容已由转换 代理(第 7.7 节)相对于源服务器的 200 (OK) 响应进行了修改。此状态码允许代理在应用了 转换时通知接收方,因为了解这一点可能会影响之后 与内容有关的决定。例如,未来对该内容的缓存验证请求 可能仅适用于相同的请求路径(通过相同的代理)。

203 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.3.5. 204 无内容

204(无内容)状态码表示服务器已成功完成 请求,并且没有其他内容要在响应内容中发送。 响应头字段中的元数据引用应用所请求操作后的目标资源及其选定表示。

例如,如果收到 204 状态码作为 PUT 请求的响应,并且 响应包含 ETag 字段,则 PUT 已成功,而 ETag 字段值包含该目标资源新 表示的实体标签。

204 响应允许服务器表示操作已成功 应用于目标资源,同时暗示用户代理不需要 离开其当前“文档视图”(如果有)。服务器假设 用户代理会根据自身界面向用户提供某种成功指示, 并将响应中的任何新增或更新元数据应用于其 活动表示。

例如,204 状态码常用于与“保存”操作相对应的文档编辑界面 ,使被保存的文档仍然 可供用户继续编辑。它也经常用于 预期自动数据传输很常见的界面,例如分布式版本 控制系统内部。

204 响应以头部部分结束而终止;它不能包含 内容或尾部字段。

204 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.3.6. 205 重置内容

205(重置内容)状态码表示服务器已完成 请求,并希望用户代理将导致 请求发送的“文档视图”重置为从源服务器接收时的原始状态。

此响应旨在支持一种常见的数据录入用例,其中用户 收到支持数据录入的内容(表单、记事本、画布等),在 该空间中输入或操作数据,使输入的数据通过 请求提交,然后重置数据录入机制以供下一次输入,使 用户可以轻松发起另一个输入操作。

由于 205 状态码意味着不会提供附加内容, 服务器不得在 205 响应中生成内容。

15.3.7. 206 部分内容

206(部分内容)状态码表示服务器正在通过传输选定表示的一个或多个部分,成功 满足目标资源的范围请求。

支持范围请求(第 14 节)的服务器通常会尝试满足所有 请求的范围,因为发送较少数据很可能导致客户端再次 请求剩余部分。但是,服务器可能出于自身原因只想发送所请求数据的一部分, 例如暂时不可用、缓存 效率、负载均衡等。由于 206 响应是自描述的, 客户端仍然可以理解只部分满足其范围 请求的响应。

客户端必须检查 206 响应的 Content-Type 和 Content-Range 字段,以确定 包含哪些部分以及是否需要其他请求。

生成 206 响应的服务器,如果以下字段本应在对同一请求的 200 (OK) 响应中发送,则除下面小节要求的字段外,必须生成这些 头字段:Date、Cache-Control、ETag、Expires、Content-Location 和 Vary。

206 响应中存在的 Content-Length 头字段 指示此消息内容中的八位字节数, 通常不是选定表示的完整长度。 每个 Content-Range 头字段 都包含有关选定表示完整长度的信息。

针对带有 If-Range 头字段的请求生成 206 响应的发送方不应该 生成所需字段之外的其他表示头字段,因为客户端 已经拥有包含这些头字段的先前响应。否则,发送方必须生成对同一请求的 200 (OK) 响应中本应发送的所有表示头字段 。

206 响应可启发式缓存;即除非 显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.3.7.1. 单个部分

如果正在传输单个部分,则生成 206 响应的服务器必须生成 Content-Range 头字段,描述所包含的选定表示范围, 并提供由该范围组成的内容。例如:

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Range: bytes 21010-47021/47022
Content-Length: 26012
Content-Type: image/gif

... 26012 字节的部分图像数据 ...
15.3.7.2. 多个部分

如果正在传输多个部分,则生成 206 响应的服务器 必须生成“multipart/byteranges”内容,如 第 14.6 节所定义,并生成一个 Content-Type 头字段, 其中包含“multipart/byteranges”媒体类型及其必需的 boundary 参数。为避免与单部分响应混淆,服务器不得在多部分响应的 HTTP 头部部分中生成 Content-Range 头字段(该字段会改为在每个部分中发送)。

在多部分内容中每个主体部分的头部区域内,服务器必须生成一个 Content-Range 头字段,对应于该主体部分中包含的范围 。如果选定表示在 200 (OK) 响应中本应具有 Content-Type 头字段,则服务器应该在每个主体 部分的头部区域中生成相同的 Content-Type 头字段。例如:

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Length: 1741
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 500-999/8000

...第一个范围...
--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 7000-7999/8000

...第二个范围
--THIS_STRING_SEPARATES--

当请求多个范围时,服务器可以合并 任何重叠的范围,或间隔小于 发送多个部分开销的范围,而不考虑相应 range-spec 在收到的 Range 头字段中出现的顺序。由于“multipart/byteranges”的每个 部分之间的典型开销约为 80 字节,具体取决于选定 表示的媒体类型和所选 boundary 参数长度,因此传输许多小的、不连续部分 可能比传输整个选定表示效率更低。

服务器不得针对单个范围的 请求生成多部分响应,因为未请求多个部分的客户端 可能不支持多部分响应。但是,如果请求了多个范围,而只有一个范围 被确定为可满足,或者合并后只剩一个范围,则服务器可以生成只有 单个主体部分的“multipart/byteranges”响应。不能 处理“multipart/byteranges”响应的客户端不得 生成请求多个范围的请求。

生成多部分响应的服务器应该按相应 range-spec 在 收到的 Range 头字段中出现的相同顺序发送各个部分,排除 被认为不可满足或被合并到其他范围中的 范围。收到多部分响应的客户端必须 检查每个主体部分中的 Content-Range 头 字段,以确定该主体部分包含哪个范围;客户端不能依赖收到与其 请求相同的范围,也不能依赖相同的请求顺序。

15.3.7.3. 组合部分

如果连接 过早关闭,或者请求使用一个或多个 Range 规范,则响应可能只传输表示的一个子范围。 经过多次此类传输后,客户端可能已经收到同一 表示的多个范围。只有当这些范围共享 相同的强验证器(第 8.8.1 节)时,才能安全地组合它们。

对目标 资源的 GET 请求收到多个部分响应的客户端,如果这些响应共享相同强验证器,则可以将其组合为更大的 连续范围。

如果最新响应是不完整的 200 (OK) 响应,则该响应的头字段 用于任何组合响应,并替换匹配的已存储 响应中的头字段。

如果最新响应是 206(部分 内容)响应,并且至少一个匹配的已存储响应是 200 (OK),则组合响应的 头字段由最新的 200 响应头字段组成。如果所有 匹配的已存储响应都是 206 响应,则使用具有 最新头字段的已存储响应作为组合响应头字段的来源, 但客户端必须使用新响应中提供的除 Content-Range 之外的其他 头字段,替换已存储响应中相应头字段的所有 实例。

组合响应内容由新响应以及所有匹配的已存储响应中的部分内容范围的并集 组成。如果该并集 构成表示的整个范围,则客户端必须像完整的 200 (OK) 响应一样处理组合响应,包括一个 反映完整长度的 Content-Length 头字段 。否则,客户端必须将连续范围集合处理为以下之一:如果组合响应是表示的前缀,则处理为不完整的 200 (OK) 响应;包含“multipart/byteranges”内容的单个 206(部分内容)响应;或者多个 206(部分内容)响应,每个响应都有一个由 Content-Range 头字段指示的连续 范围。

15.4. 重定向 3xx

3xx(重定向)类别的状态码表示用户代理需要采取 进一步操作才能完成请求。有几种类型的 重定向:

  1. 表示该资源可能在不同 URI 上可用的重定向,该 URI 由 Location 头字段提供,例如 状态码 301(永久移动)、 302(找到)、307(临时重定向)和 308(永久重定向)。
  2. 在能够表示 此资源的匹配资源之间提供选择的重定向,例如 300(多种 选择)状态码。
  3. 重定向到由 Location 头字段标识的不同资源,该资源可以表示对请求的间接响应 ,例如 303(查看其他) 状态码。
  4. 重定向到先前存储的结果,例如 304(未修改)状态码。

如果提供了 Location 头字段(第 10.2.2 节),即使不理解具体的 状态码,用户代理也可以自动将请求重定向到 Location 字段值引用的 URI。对于 未知为安全的方法,自动重定向需要谨慎执行,如 第 9.2.1 节所定义,因为用户可能不 希望重定向不安全的请求。

自动跟随重定向请求时,用户代理应该重新发送原始请求消息,并进行以下 修改:

  1. 将目标 URI 替换为重定向响应的 Location 头字段值引用的 URI,并在替换前相对于原始请求的目标 URI 对其进行解析 。

  2. 删除由实现自动生成的头字段, 并视新请求需要以更新后的值替换它们。这 包括:

    1. 特定于连接的头字段(参见 第 7.6.1 节),
    2. 特定于客户端代理配置的头字段,包括 (但不限于)Proxy-Authorization,
    3. 特定于源的头字段(如果有),包括(但不限于) Host,
    4. 由实现缓存添加的验证头字段 (例如 If-None-Match、If-Modified-Since), 以及
    5. 特定于资源的头字段,包括(但不限于)Referer、Origin、Authorization 和 Cookie。
  3. 考虑删除并非由实现自动生成的头字段 (即因为调用上下文添加而存在于请求中的字段), 如果存在安全影响;这包括但不限于 Authorization 和 Cookie。

  4. 如果适用,根据重定向状态码的 语义更改请求方法。

  5. 如果请求方法已更改为 GET 或 HEAD,则删除 特定于内容的头字段,包括(但不限于)Content-Encoding、Content-Language、Content-Location、Content-Type、Content-Length、Digest、Last-Modified。

客户端应该检测并介入循环重定向 (即“无限”重定向循环)。

15.4.1. 300 多种选择

300(多种选择)状态码表示目标资源具有多个表示,每个表示都有自己更具体的 标识符,并提供有关替代项的信息, 以便用户(或用户代理)可以通过将其请求重定向到 一个或多个这些标识符来选择首选表示。换言之, 服务器希望用户代理参与反应式协商,以选择最适合其需求的表示 (第 12 节)。

如果服务器有首选项,则服务器应该 生成包含该首选项 URI 引用的 Location 头字段 。用户代理可以使用 Location 字段值进行自动重定向。

对于 HEAD 以外的请求方法,服务器应该 在 300 响应中生成包含表示元数据 和 URI 引用列表的内容,用户或用户代理可以从中选择最 首选的一个。如果用户代理理解所提供的媒体类型,则可以从该列表中自动进行选择 。本规范未定义 自动选择的特定格式,因为 HTTP 试图 与其内容定义保持正交。实际中,表示 通常以某种被认为用户 代理可以接受的易于解析格式提供,该判断基于共同设计或内容协商,或者使用某种普遍 接受的超文本格式。

300 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.4.2. 301 永久移动

301(永久移动)状态码表示目标资源已分配新的永久 URI,未来对该资源的任何 引用都应当使用所包含的 URI 之一。服务器 建议具有链接编辑能力的用户代理可以永久替换 对目标 URI 的引用,将其替换为服务器发送的新引用之一 。但是,除非用户代理正在主动 编辑引用(例如正在创作内容)、连接是安全的, 且源服务器是所编辑内容的可信权威方,否则通常会忽略此建议。

服务器应该在响应中生成 Location 头字段,其中包含新永久 URI 的首选 URI 引用。用户代理可以 使用 Location 字段值进行自动重定向。服务器的响应 内容通常包含带有指向新 URI 的超链接的简短超文本说明。

301 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.4.3. 302 找到

302(找到)状态码表示目标资源暂时 位于不同 URI。由于重定向可能偶尔发生变化, 客户端应当继续使用目标 URI 进行未来请求。

服务器应该在响应中生成 Location 头字段,其中包含不同 URI 的 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。服务器的响应内容 通常包含带有指向不同 URI 的超链接的简短超文本说明。

15.4.4. 303 查看其他

303(查看其他)状态码表示服务器正在将用户 代理重定向到不同资源,该资源由 Location 头字段中的 URI 指示,旨在 提供对原始请求的间接响应。用户代理可以执行以该 URI 为目标的 检索请求(如果使用 HTTP,则为 GET 或 HEAD 请求),该请求 也可能再次重定向,并将最终结果作为原始请求的答案 呈现。请注意,Location 头字段中的新 URI 不 被视为与目标 URI 等价。

此状态码适用于任何 HTTP 方法。它主要用于允许 POST 操作的输出将用户代理重定向到不同资源,因为 这样可以将对应于 POST 响应的信息作为一个 可单独标识、收藏和缓存的资源提供。

对 GET 请求的 303 响应表示源服务器没有 能够由服务器通过 HTTP 传输的目标资源 表示。但是,Location 字段值引用 一个描述目标资源的资源,使得对该其他资源发出检索 请求可能产生对接收方有用的表示, 而不意味着该表示代表原始目标资源。请 注意,什么可以被表示、什么样的表示足够、 什么可能是有用描述等问题超出了 HTTP 的范围。

除对 HEAD 请求的响应外,303 响应的表示应当 包含带有指向 Location 头字段中所提供同一 URI 引用的超链接的简短超文本说明。

15.4.5. 304 未修改

304(未修改)状态码表示已收到条件 GET 或 HEAD 请求, 如果不是因为条件求值为 false,本应产生 200 (OK) 响应。换言之,服务器无需 传输目标资源的表示,因为请求表明 使请求带条件的客户端已经具有有效表示; 因此服务器将客户端重定向到使用该已存储的 表示,就像它是 200 (OK) 响应的内容一样。

生成 304 响应的服务器必须生成以下任何 本应在对同一请求的 200 (OK) 响应中发送的头字段:

由于 304 响应的目标是在接收方已经拥有一个或多个缓存表示时尽量减少信息传输 ,发送方不应该生成上述字段之外的表示元数据, 除非该元数据用于指导缓存 更新(例如,如果响应没有 ETag 字段,则 Last-Modified 可能 有用)。

收到 304 响应的缓存的要求定义于 [CACHING] 的第 4.3.4 节。如果条件请求 源自出站客户端,例如具有自身缓存的用户代理向共享代理发送 条件 GET,则代理应该 将 304 响应转发给该客户端。

304 响应以头部部分结束而终止;它不能包含 内容或尾部字段。

15.4.6. 305 使用代理

305(使用代理)状态码在本 规范的早期版本中定义,现在已弃用([RFC7231] 的附录 B)。

15.4.7. 306(未使用)

306 状态码在本规范的早期版本中定义,现在 不再使用,并且该代码已保留。

15.4.8. 307 临时重定向

307(临时重定向)状态码表示目标资源暂时位于不同 URI, 如果用户代理自动重定向到该 URI,则不得更改 请求方法。由于 重定向可能随时间变化,客户端应当继续使用原始 目标 URI 进行未来请求。

服务器应该在响应中生成 Location 头字段,其中包含不同 URI 的 URI 引用。用户代理可以使用 Location 字段值进行自动重定向。服务器的响应内容 通常包含带有指向不同 URI 的超链接的简短超文本说明。

15.4.9. 308 永久重定向

308(永久重定向)状态码表示目标资源已分配新的 永久 URI,未来对该资源的任何引用都应当使用所包含的 URI 之一。服务器建议具有链接编辑 能力的用户代理可以永久替换对目标 URI 的引用,将其替换为服务器发送的新 引用之一。但是,除非 用户代理正在主动编辑引用(例如正在创作内容)、 连接是安全的,并且源服务器是所编辑 内容的可信权威方,否则通常会忽略此建议。

服务器应该在响应中生成 Location 头字段,其中包含新永久 URI 的首选 URI 引用。用户代理可以 使用 Location 字段值进行自动重定向。服务器的响应 内容通常包含带有指向新 URI 的超链接的简短超文本说明。

308 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.5. 客户端错误 4xx

4xx(客户端错误)类别的状态码表示客户端似乎 出错了。除响应 HEAD 请求外,服务器应该发送一个表示,其中包含对 错误情况的解释,以及它是临时还是永久状况。这些状态 码适用于任何请求方法。用户代理应该 向用户显示所包含的任何表示。

15.5.1. 400 错误请求

400(错误请求)状态码表示服务器由于被认为是客户端错误的原因(例如 格式错误的请求语法、无效的请求消息分帧或欺骗性请求 路由),无法或不愿 处理该请求。

15.5.2. 401 未授权

401(未授权)状态码表示请求尚未应用, 因为它缺少目标资源的有效身份验证凭据。生成 401 响应的 服务器必须发送 WWW-Authenticate 头字段 (第 11.6.1 节),其中包含至少一个 适用于目标资源的质询。

如果请求包含身份验证凭据,则 401 响应表示 这些凭据的授权已被拒绝。用户代理可以使用新的或替换后的 Authorization 头字段(第 11.6.2 节)重复请求。如果 401 响应包含与先前响应相同的 质询,并且用户代理已经至少尝试过一次身份验证 ,那么用户代理应该 向用户呈现所包含的表示,因为其中通常包含相关 诊断信息。

15.5.3. 402 需要付款

402(需要付款)状态码保留供未来使用。

15.5.4. 403 禁止

403(禁止)状态码表示服务器理解该请求,但 拒绝完成它。希望公开说明请求为何被 禁止的服务器可以在响应内容(如果有)中描述该原因。

如果请求中提供了身份验证凭据,则服务器认为这些凭据 不足以授予访问权限。客户端不应该 使用相同凭据自动重复请求。客户端可以使用新的或不同的凭据重复请求。 但是,请求也可能因为与凭据无关的原因而被禁止。

希望“隐藏”被禁止的目标资源当前存在这一事实的源服务器可以改为以 404(未找到)状态码响应。

15.5.5. 404 未找到

404(未找到)状态码表示源服务器未找到目标 资源的当前表示,或者不愿披露存在这样的表示。404 状态码 并不表明这种缺少表示的情况是临时还是永久;如果 源服务器知道(可能通过某些可配置方式)该 状况可能是永久的,则应当优先使用 410(已消失)状态码而不是 404 。

404 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.5.6. 405 方法不允许

405(方法不允许)状态码表示请求行中收到的方法 是源服务器已知的,但目标资源不支持该方法。源服务器必须在 405 响应中生成 Allow 头字段,其中包含 目标资源当前支持的方法列表。

405 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.5.7. 406 不可接受

406(不可接受)状态码表示根据请求中收到的主动协商头 字段(第 12.1 节),目标资源没有用户代理可以接受的当前表示 ,并且服务器不愿提供默认表示。

服务器应该生成包含 可用表示特征及相应资源标识符列表的内容,用户或用户代理可以从中选择最合适的项。用户代理可以自动从 该列表中选择最合适的项。但是,本规范没有为这种 自动选择定义任何标准,如 第 15.4.1 节所述。

15.5.8. 407 需要代理身份验证

407(需要代理身份验证)状态码类似于 401(未授权),但它表示 客户端需要验证自身身份才能为此请求使用代理。 代理必须发送一个 Proxy-Authenticate 头字段(第 11.7.1 节),其中包含适用于 该代理的质询。客户端可以使用新的或替换后的 Proxy-Authorization 头字段(第 11.7.2 节)重复 请求。

15.5.9. 408 请求超时

408(请求超时)状态码表示服务器在其愿意等待的时间内未收到 完整的请求消息。

如果客户端有一个仍在传输中的未完成请求,则可以 重复该请求。如果当前连接不可用(例如在 HTTP/1.1 中由于请求定界丢失而发生这种情况),则会使用新连接。

15.5.10. 409 冲突

409(冲突)状态码表示由于与目标资源当前状态 冲突,请求无法完成。此代码用于 用户可能能够解决冲突并重新提交 请求的情况。服务器应该生成包含 足够信息以让用户识别冲突来源的内容。

冲突最可能发生在对 PUT 请求的响应中。例如,如果 使用版本控制,而被 PUT 的表示包含对资源的修改, 且这些修改与更早的(第三方)请求所做修改冲突,则 源服务器可以使用 409 响应表示它无法完成 请求。在这种情况下,响应表示很可能包含 有助于根据修订历史合并差异的信息。

15.5.11. 410 已消失

410(已消失)状态码表示源服务器不再提供对目标资源的访问, 并且这种状况可能是永久的。如果源服务器不知道, 或无法确定该状况是否永久, 则应当改用状态码 404(未找到) 。

410 响应主要用于协助 Web 维护工作, 通知接收方该资源有意不可用,并且 服务器所有者希望删除指向该资源的远程链接。这种事件 常见于限时的促销服务,也常见于属于 已不再与源服务器站点有关联的个人的资源。不必 将所有永久不可用的资源都标记为“gone”,也无需将该标记保留任何 时长——这由服务器所有者自行决定。

410 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.5.12. 411 需要长度

411(需要长度)状态码表示服务器拒绝接受 没有定义 Content-Length 的请求(第 8.6 节)。 如果客户端添加有效的 Content-Length 头字段,其中包含请求内容的长度,则可以重复请求 。

15.5.13. 412 前置条件失败

412(前置条件失败)状态码表示请求头字段中给出的一个或多个条件 在服务器上测试时求值为 false(第 13 节)。此 响应状态码允许客户端对当前 资源状态(其当前表示和元数据)设置前置条件,从而在目标资源处于意外状态时阻止 请求方法被应用。

15.5.14. 413 内容过大

413(内容过大)状态码表示服务器拒绝 处理请求,因为请求内容大于服务器愿意 或能够处理的大小。如果所使用的协议版本允许,服务器可以终止请求; 否则,服务器可以关闭连接。

如果该状况是临时的,则服务器应该生成 Retry-After 头字段,以指示 该状况是临时的,以及客户端何时可以再次 尝试。

15.5.15. 414 URI 过长

414(URI 过长)状态码表示服务器拒绝为 请求提供服务,因为目标 URI 长于服务器愿意 解释的长度。这种罕见情况只可能发生在客户端错误地 将具有长查询信息的 POST 请求转换为 GET 请求时、客户端 陷入无限重定向循环时(例如,重定向 URI 前缀指向其自身的后缀),或者服务器正受到试图 利用潜在安全漏洞的客户端攻击时。

414 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.5.16. 415 不支持的媒体类型

415(不支持的媒体类型)状态码表示源服务器 拒绝为请求提供服务,因为内容采用目标资源上的此方法不支持的格式。

格式问题可能是由于请求指示的 Content-Type 或 Content-Encoding,也可能是 直接检查数据的结果。

如果问题是由不支持的内容编码导致的,则应当使用 Accept-Encoding 响应头 字段(第 12.5.3 节)指示请求中哪些 内容编码(如果有)会被接受。

另一方面,如果原因是不支持的媒体类型,则可以使用 Accept 响应头字段(第 12.5.1 节)指示请求中哪些媒体类型会被接受 。

15.5.17. 416 范围不可满足

416(范围不可满足)状态码表示 请求的 Range 头字段(第 14.2 节) 中的范围集合已被拒绝,要么因为所有请求的范围都不可满足,要么 因为客户端请求了过多的小范围或重叠范围 (潜在的拒绝服务攻击)。

每个范围单位都定义其自身范围集合满足要求所需的条件。 例如,第 14.1.2 节定义 bytes 范围集合可满足的条件。

生成针对字节范围请求的 416 响应的服务器应该生成 Content-Range 头字段,指定选定表示的当前长度 (第 14.4 节)。

例如:

HTTP/1.1 416 Range Not Satisfiable
Date: Fri, 20 Jan 2012 15:41:54 GMT
Content-Range: bytes */47022

15.5.18. 417 期望失败

417(期望失败)状态码表示请求的 Expect 头字段(第 10.1.1 节)中给出的期望无法由至少一个入站服务器满足。

15.5.19. 418(未使用)

[RFC2324] 是一份 4 月 1 日发布的 RFC,用来讽刺 HTTP 被滥用的各种方式;其中一种滥用 是定义一个特定于应用程序的 418 状态码,该代码 作为玩笑被部署得足够多,以至于无法用于未来任何用途。

因此,418 状态码在 IANA HTTP 状态码注册表中被保留。 这表示该状态码目前不能分配给其他应用 。如果未来情况需要使用它(例如 4NN 状态 码耗尽),可以重新分配给其他用途。

15.5.20. 421 错误定向的请求

421(错误定向的请求)状态码表示请求被定向到 无法或不愿为目标 URI 生成权威响应的服务器 。源服务器(或代表源服务器行事的网关) 发送 421 以拒绝与服务器已配置的源(第 4.3.1 节)不匹配,或者与接收请求的连接上下文不匹配的 目标 URI(第 7.4 节)。

收到 421(错误定向的请求)响应的客户端可以通过不同连接重试请求,无论请求方法是否 幂等,例如建立特定于目标 资源源的新连接,或者通过替代服务 [ALTSVC]。

代理不得生成 421 响应。

15.5.21. 422 无法处理的内容

422(无法处理的内容)状态码表示服务器理解 请求内容的内容类型(因此 415 (不支持的媒体类型)状态码不合适),并且 请求内容的语法正确,但无法处理其中包含的 指令。例如,如果 XML 请求内容 包含格式良好(即语法正确)但语义错误的 XML 指令,则可以发送此状态码。

15.5.22. 426 需要升级

426(需要升级)状态码表示服务器拒绝使用 当前协议执行请求,但在客户端升级到其他协议后 可能愿意这样做。服务器必须在 426 响应中发送 Upgrade 头字段 以指示所需协议(第 7.8 节)。

示例:

HTTP/1.1 426 Upgrade Required
Upgrade: HTTP/3.0
Connection: Upgrade
Content-Length: 53
Content-Type: text/plain

此服务要求使用 HTTP/3.0 协议。

15.6. 服务器错误 5xx

5xx(服务器错误)类别的状态码表示服务器意识到自己 出错或无法执行所请求的方法。除响应 HEAD 请求外,服务器应该发送一个表示, 其中包含对错误情况的解释,以及它是临时还是 永久状况。用户代理应该向用户显示任何包含的 表示。这些状态码适用于任何请求方法。

15.6.1. 500 内部服务器错误

500(内部服务器错误)状态码表示服务器遇到 意外状况,导致其无法完成请求。

15.6.2. 501 未实现

501(未实现)状态码表示服务器不支持 完成请求所需的功能。当 服务器无法识别请求方法,并且无法为任何资源支持该方法时,这是适当的响应 。

501 响应可启发式缓存;即除非 方法定义或显式缓存控制另有指示(参见 [CACHING] 的第 4.2.2 节)。

15.6.3. 502 错误网关

502(错误网关)状态码表示服务器在充当 网关或代理时,在尝试完成请求的过程中从其访问的入站服务器收到无效响应 。

15.6.4. 503 服务不可用

503(服务不可用)状态码表示服务器当前 由于临时过载或计划维护而无法处理请求, 这种状况可能在延迟一段时间后缓解。服务器可以发送 Retry-After 头字段(第 10.2.3 节),以 建议客户端在重试 请求之前等待适当的时长。

15.6.5. 504 网关超时

504(网关超时)状态码表示服务器在充当 网关或代理时,没有及时从完成请求所需访问的上游服务器收到响应 。

15.6.6. 505 不支持的 HTTP 版本

505(不支持的 HTTP 版本)状态码表示服务器不 支持或拒绝支持请求消息中使用的 HTTP 主版本。服务器表示除发送此错误消息外,它无法或不愿使用与客户端相同的主版本完成 请求,如 第 2.5 节所述 。服务器应该为 505 响应生成一个表示,描述为何不支持该版本 以及该服务器支持哪些其他协议。

16. 扩展 HTTP

HTTP 定义了许多通用扩展点,可用于在不引入新版本的情况下向协议引入功能 ,包括方法、状态码、字段 名称,以及已定义字段中的其他扩展点,例如身份验证 方案和缓存指令 (参见 第 5.2.3 节,见 [CACHING])。由于 HTTP 的语义没有 版本之分,这些扩展点是持久的;所使用的协议版本 不会影响其语义。

不鼓励与版本无关的扩展依赖或与 所使用协议的特定版本交互。当无法避免时,需要仔细考虑 扩展如何跨版本互操作。

此外,HTTP 的特定版本可能有自己的扩展点,例如 HTTP/1.1 中的传输编码 (第 6.1 节,见 [HTTP/1.1]) 和 HTTP/2 SETTINGS 或帧类型 ([HTTP/2])。这些扩展点特定于 它们所在的协议版本。

特定于版本的扩展不能覆盖或修改与版本无关的 机制或扩展点 (例如方法或头字段) 的语义,除非该协议元素明确 允许这样做。例如,CONNECT 方法 (第 9.3.6 节) 允许这样做。

这些指南确保协议能够正确且可预测地运行,即使路径的不同部分 实现了不同版本的 HTTP。

16.1. 方法可扩展性

16.1.1. 方法注册表

由 IANA 在 https://www.iana.org/assignments/http-methods 维护的“超文本传输协议 (HTTP) 方法注册表”注册 method 名称。

HTTP 方法注册必须包含以下字段:

添加到此命名空间的值需要 IETF 审查 (参见 [RFC8126], 第 4.8 节)。

16.1.2. 新方法的注意事项

标准化方法是通用的;也就是说,它们可能适用于任何 资源,而不只是某一种特定媒体类型、资源种类或应用程序。因此, 最好在不特定于单一应用程序或数据格式的文档中注册新方法 ,因为正交技术 应有正交规范。

由于消息解析 (第 6 节) 需要独立于方法 语义 (对 HEAD 的响应除外),新方法的定义不能改变 解析算法,也不能禁止请求或 响应消息中存在内容。新方法的定义可以通过要求值为 "0" 的 Content-Length 头字段 ,规定只允许零长度 内容。

同样,新方法不能使用分别允许用于 CONNECT 和 OPTIONS 的特殊 host:port 和星号形式的请求 目标 (第 7.1 节)。目标 URI 需要完整的绝对 形式 URI,这意味着请求目标需要以绝对形式 发送,或者目标 URI 将以与其他方法相同的方式从请求 上下文中重构。

新方法定义需要说明它是否安全 (第 9.2.1 节)、幂等 (第 9.2.2 节)、 可缓存 (第 9.2.3 节)、请求内容 (如果有) 应关联什么语义 ,以及该方法对头字段或状态码 语义作出哪些细化。如果新方法可缓存,其定义应当描述缓存如何以及 在什么条件下可以存储响应并用它满足 后续请求。新方法应当描述它是否可以设置 条件 (第 13.1 节),以及 如果可以,在条件为 false 时服务器如何响应。同样,如果新 方法可能对部分响应语义 (第 14.2 节) 有某种用途,也应当 对此进行说明。

16.2. 状态码可扩展性

16.2.1. 状态码注册表

由 IANA 在 https://www.iana.org/assignments/http-status-codes 维护的“超文本传输协议 (HTTP) 状态码注册表”注册 状态码编号。

注册必须包含以下字段:

  • 状态码 (3 位数字)
  • 简短描述
  • 指向规范文本的指针

添加到 HTTP 状态码命名空间的值需要 IETF 审查 (参见 [RFC8126], 第 4.8 节)。

16.2.2. 新状态码的注意事项

当需要表达当前状态码未定义的响应语义时, 可以注册新的状态码。状态码是通用的; 它们可能适用于任何资源,而不只是某一种特定媒体类型、 资源种类或 HTTP 应用程序。因此,最好在 不特定于单一应用程序的文档中注册新状态码。

新状态码必须属于 第 15 节定义的类别之一。为了允许现有 解析器处理响应消息,新状态码不能禁止内容, 但可以规定内容长度为零。

尚未广泛部署的新状态码提案应当避免 在明确达成将其注册的共识之前为其分配具体编号; 相反,早期草案可以使用诸如 "4NN" 或 "3N0" .. "3N9" 的表示法,以指示所提议状态码的类别,而不会过早占用 编号。

新状态码的定义应当说明会导致包含该状态码的响应的请求条件 (例如,请求 头字段和/或方法的组合),以及对响应头 字段的任何依赖 (例如,哪些字段是必需的,哪些字段可以修改语义,以及 与新状态码一起使用时哪些字段语义会进一步细化)。

默认情况下,状态码仅适用于它所在响应对应的请求 。如果状态码适用于更大的适用范围 — 例如, 对相关资源的所有请求或对服务器的所有请求 — 则必须 明确指定。这样做时,应注意不能期望所有客户端 都一致地应用更大的范围,因为它们可能不 理解新的状态码。

新的最终状态码定义应当指定它是否 可启发式缓存。请注意,如果响应具有显式新鲜度信息,则任何带最终状态码的响应都可以 缓存。定义为 可启发式缓存的状态码允许在没有显式新鲜度 信息的情况下缓存。同样,如果使用 must-understand 缓存指令,状态码定义可以对 缓存行为施加约束。有关更多信息,请参见 [CACHING]。

最后,新状态码的定义应当指出内容是否 与已标识资源存在任何隐含关联 (第 6.4.2 节)。

16.3. 字段可扩展性

HTTP 最广泛使用的扩展点是定义新的头字段和尾部 字段。

可以定义新字段,使其在被接收方理解时, 覆盖或增强对先前已定义字段的解释,定义 请求求值的前置条件,或细化响应的含义。

但是,定义字段并不能保证接收方会部署或识别它。 大多数字段的设计都预期接收方可以安全地忽略 (但 向下游转发) 任何无法识别的字段。在其他情况下,发送方理解给定字段的能力 可能由其先前的通信表明,也许是在 协议版本、其先前消息中发送的字段,或其对特定 媒体类型的使用中表明。同样,如果在引入字段时同时定义了检查方式,则可以通过 OPTIONS 请求或通过与已定义的众所周知 URI [RFC8615] 交互来直接检查支持情况。

16.3.1. 字段名称注册表

“超文本传输协议 (HTTP) 字段名称注册表”定义 HTTP 字段名称的命名空间 。

任何一方都可以请求注册 HTTP 字段。有关创建新 HTTP 字段时 需要考虑的事项,请参见 第 16.3.2 节。

“超文本传输协议 (HTTP) 字段名称注册表”位于 https://www.iana.org/assignments/http-fields/。 可以按照其中的说明提交注册请求,或者向 "ietf-http-wg@w3.org" 邮件列表发送电子邮件。

字段名称根据指定专家 (由 IESG 或其代表任命) 的建议进行注册。状态为 'permanent' 的字段需要规范 ([RFC8126], 第 4.6 节)。

注册请求包含以下信息:

字段名称:
所请求的字段名称。它必须符合 第 5.1 节定义的 field-name 语法,并且应该仅限于字母、 数字和连字符 ('-'),且第一个字符应为字母。
状态:
"permanent"、"provisional"、"deprecated" 或 "obsoleted"。
规范文档:
对规定该字段的文档的引用,最好包含可用于获取该文档副本的 URI 。对于 provisional 注册而言是可选的,但建议提供。也可以包含相关章节的指示 ,但不是必需的。

以及可选地:

注释:
附加信息,例如有关保留条目的信息。

专家可以与社区协商,在注册表中定义需要收集的其他字段 。

标准定义的名称状态为 "permanent"。如果专家在与社区协商后发现其他名称正在使用, 也可以将其注册为 permanent 。其他名称应当注册为 "provisional"。

如果专家在与社区协商后发现 provisional 条目未被使用, 可以将其移除。专家可以随时将 provisional 条目的状态更改为 permanent。

请注意,如果专家确定未注册的名称已经广泛部署,并且 不太可能及时通过其他方式注册,则第三方 (包括专家) 可以注册该名称。

16.3.2. 新字段的注意事项

HTTP 头字段和尾部字段是协议广泛使用的扩展点。 虽然它们可以临时使用,但打算更广泛使用的字段 需要仔细记录,以确保互操作性。

特别是,建议定义新字段的规范作者考虑 并在适当情况下记录以下方面:

  • 在什么条件下可以使用该字段;例如,仅在响应或 请求中、在所有消息中、仅在对特定请求方法的响应中 等。
  • 字段语义是否会由其上下文进一步细化,例如与 某些请求方法或状态码一起使用时。
  • 所传达信息的适用范围。默认情况下,字段 仅适用于与其关联的消息,但某些响应字段被 设计为适用于资源的所有表示、资源本身或 更广范围。扩展响应字段范围的规范 需要仔细考虑内容协商、适用 时间段以及 (在某些情况下) 多租户服务器部署等问题。
  • 在什么条件下允许中间方插入、删除或修改 字段值。
  • 是否允许该字段出现在尾部;默认情况下不允许 (参见 第 6.5.1 节)。
  • 在 Connection 头字段中列出该字段名称是否适当甚至必需 (即 该字段是否逐跳;参见 第 7.6.1 节)。
  • 该字段是否引入任何附加安全考虑,例如 披露与隐私有关的数据。

如果默认行为不适当,请求头字段还有其他需要记录的注意事项 :

  • 在 Vary 响应头字段中列出该字段名称是否适当 (例如,当请求头 字段被源服务器的内容选择算法使用时;参见 第 12.5.5 节)。
  • 如果该字段在 PUT 请求中收到,是否打算存储它 (参见 第 9.3.4 节)。
  • 由于安全考虑自动重定向请求时,该字段是否应当移除 (参见 第 15.4 节)。
16.3.2.1. 新字段 名称的注意事项

建议定义新字段的规范作者选择简短但 描述性的字段名称。短名称避免不必要的数据传输; 描述性名称避免混淆以及对可能具有更广泛用途的名称进行“抢占” 。

为此,鼓励用途有限的字段 (例如仅限于单个 应用程序或用例的头字段) 使用包含该用途 (或 缩写) 作为前缀的名称;例如,如果 Foo Application 需要 Description 字段,它可以使用 "Foo-Desc";"Description" 过于通用,而 "Foo-Description" 又不必要地过长。

虽然 field-name 语法定义为允许任何 token 字符,但实际中 某些实现会限制它们接受的字段名称字符。 为实现互操作性,新字段名称应该限制为 字母数字字符、"-" 和 ".",并且应该以字母开头。例如,下划线 ("_") 字符在通过非 HTTP 网关 接口传递时可能出现问题 (参见 第 17.10 节)。

字段名称不应以 "X-" 为前缀;有关更多信息,请参见 [BCP178]。

HTTP 字段名称中有时使用其他前缀;例如,"Accept-" 被 用于许多内容协商头字段,而 "Content-" 的使用如 第 6.4 节所述。这些前缀仅 帮助识别字段用途,并不会触发自动 处理。

16.3.2.2. 新字段 值的注意事项

定义新 HTTP 字段的一项主要任务是规定 字段值语法:发送方应该生成什么,以及接收方应如何 从收到的内容推断语义。

鼓励 (但不要求) 作者使用本 规范中的 ABNF 规则或 [RFC8941]中的规则来定义 新字段值的语法。

建议作者仔细考虑多个字段 行的组合会如何影响它们 (参见 第 5.3 节)。由于发送方可能错误地发送多个值,并且 中间方和 HTTP 库都可能自动进行组合,这 适用于所有字段值 — 即使只预期单个值。

因此,建议作者对包含逗号的值进行分隔或编码 (例如,使用 quoted-string 规则,见 第 5.6.4 节,使用 [RFC8941]的 String 数据类型,或 特定于字段的编码)。这样可确保字段数据中的逗号不会 与分隔列表值的逗号混淆。

例如,Content-Type 字段值仅允许引号字符串内出现逗号,即使存在多个值,也可以可靠地 解析。Location 字段值提供了一个不应 仿效的反例:由于 URI 可以包含逗号,因此无法可靠地 区分包含逗号的单个值和两个值。

此外,建议具有单值字段 (参见 第 5.5 节) 的作者记录 当存在多个成员时应如何处理消息 (合理的默认行为 是忽略该字段,但这并不一定总是正确选择)。

16.4. 身份验证方案可扩展性

16.4.1. 身份验证方案注册表

“超文本传输协议 (HTTP) 身份验证方案注册表”定义 质询和凭据中身份验证方案的命名空间。它 维护于 https://www.iana.org/assignments/http-authschemes。

注册必须包含以下字段:

  • 身份验证方案名称
  • 指向规范文本的指针
  • 注释 (可选)

添加到此命名空间的值需要 IETF 审查 (参见 [RFC8126], 第 4.8 节)。

16.4.2. 新身份验证 方案的注意事项

HTTP 身份验证框架的某些方面会对 新身份验证方案的工作方式施加约束:

  • HTTP 身份验证被假定为无状态的:验证请求所需的所有信息 必须在 请求中提供,而不是依赖服务器 记住先前请求。基于底层连接或与其绑定的身份验证 超出本规范的范围,并且 天生存在缺陷,除非采取措施确保该连接 不能被经过身份验证的用户之外的任何一方使用 (参见 第 3.3 节)。

  • 身份验证参数 "realm" 保留用于定义保护 空间,如 第 11.5 节所述。 新方案不得以与该定义不兼容的方式使用它 。

  • "token68" 表示法是为了与现有 身份验证方案兼容而引入的,并且每个质询或 凭据只能使用一次。因此,新方案应当改用 auth-param 语法 ,否则将无法进行未来扩展。

  • 质询和凭据的解析由本 规范定义,不能由新的身份验证方案修改。当 使用 auth-param 语法时,所有参数都应当同时支持 token 和 quoted-string 语法,并且语法约束应当 定义在解析后的字段值上 (即 quoted-string 处理之后)。这是必要的,以便接收方可以使用适用于所有身份验证方案的通用 解析器。

    注意:将 "realm" 参数的值语法 限制为 quoted-string 是一个不应在 新参数中重复的糟糕设计选择。

  • 新方案的定义应当规定如何处理未知的 扩展参数。一般而言,"must-ignore" 规则优于 "must-understand" 规则,因为否则在存在旧版接收方时将难以引入 新参数。此外,最好描述定义新参数的策略 (例如 "更新 规范" 或 "使用此注册表")。

  • 身份验证方案需要记录它们是否可用于 源服务器身份验证 (即使用 WWW-Authenticate), 和/或代理身份验证 (即使用 Proxy-Authenticate)。

  • Authorization 头字段中携带的凭据特定于用户 代理,因此在它们出现的请求范围内,对 HTTP 缓存具有与 "private" 缓存响应指令 (第 5.2.2.7 节,见 [CACHING]) 相同的效果 。

    因此,选择不在 Authorization 头字段中携带凭据的新身份验证方案 (例如使用新 定义的头字段) 将需要通过规定使用 缓存响应指令 (例如 "private") 来明确禁止缓存。

  • 使用 Authentication-Info、Proxy-Authentication-Info 或任何其他 与身份验证相关的响应头字段的方案,需要考虑并 记录相关安全考虑 (参见 第 17.16.4 节)。

16.5. 范围单位可扩展性

16.5.1. 范围单位注册表

“HTTP 范围单位注册表”定义范围单位名称的命名空间,并 引用其相应规范。它维护于 https://www.iana.org/assignments/http-parameters。

HTTP 范围单位的注册必须包含以下 字段:

  • 名称
  • 描述
  • 指向规范文本的指针

添加到此命名空间的值需要 IETF 审查 (参见 [RFC8126], 第 4.8 节)。

16.5.2. 新范围单位的注意事项

其他范围单位,例如页面、章节、记录、 行或时间等特定于格式的边界,可能可在 HTTP 中用于特定于应用程序的用途,但 实际中并不常用。替代范围单位的实现者应当 考虑它们如何与内容编码和通用 中间方一起工作。

16.6. 内容编码可扩展性

16.6.1. 内容编码注册表

由 IANA 在 https://www.iana.org/assignments/http-parameters/ 维护的“HTTP 内容编码注册表”注册 content-coding 名称。

内容编码注册必须包含以下 字段:

  • 名称
  • 描述
  • 指向规范文本的指针

内容编码的名称不得与 传输编码的名称重叠 (根据位于 https://www.iana.org/assignments/http-parameters/ 的“HTTP 传输编码注册表”) ,除非编码转换完全相同 (如 第 8.4.1 节定义的压缩编码那样)。

添加到此命名空间的值需要 IETF 审查 (参见 第 4.8 节 ,见 [RFC8126]) 并且必须符合 第 8.4.1 节定义的内容编码用途 。

16.6.2. 新内容 编码的注意事项

新的内容编码应当尽可能是自描述的,可选 参数可在编码格式本身内部发现,而不是依赖 传输过程中可能丢失的外部元数据。

16.7. Upgrade 令牌注册表

“超文本传输协议 (HTTP) Upgrade 令牌注册表”定义用于在 Upgrade 头字段中标识协议的 protocol-name 令牌命名空间。该注册表维护于 https://www.iana.org/assignments/http-upgrade-tokens。

每个已注册协议名称都与联系信息和一组可选 规范关联,这些规范详细说明连接升级后将如何 处理。

注册按“先到先得”原则进行 (参见 [RFC8126] 的第 4.4 节) 并受以下规则约束:

  1. protocol-name 令牌一旦注册,将永久保持注册。
  2. protocol-name 令牌不区分大小写,并以发送方生成时首选的大小写形式 注册。
  3. 注册必须为该 注册指定责任方。
  4. 注册必须指定联系人。
  5. 注册可以指定与 该令牌相关联的一组规范。此类规范无需公开。
  6. 注册应该指定注册时与该令牌相关联的一组预期 "protocol-version" 令牌。
  7. 责任方可以随时更改注册 。IANA 将保留所有此类更改的记录,并在 请求时提供。
  8. IESG可以重新分配协议令牌的责任方。 这通常只会在无法联系责任方的情况下使用 。

17. 安全考虑

本节旨在向开发者、信息提供者和用户说明 与 HTTP 语义及其通过 Internet 传输信息的使用相关的已知安全问题 。与缓存相关的考虑见 [CACHING] 的第 7 节,与 HTTP/1.1 消息语法和解析相关的考虑见 [HTTP/1.1] 的第 11 节。

下面的注意事项列表并不详尽。与 HTTP 语义相关的大多数安全问题涉及保护服务器端应用程序 (HTTP 接口背后的代码) 、保护用户代理对通过 HTTP 收到内容的处理,或安全使用 Internet 一般而言,而不是协议本身的安全。对 HTTP 运行至关重要的 URI 安全考虑见 [URI] 的第 7 节。多个 组织维护 Web 应用程序安全主题信息及当前研究链接 (例如 [OWASP])。

17.1. 建立权威性

HTTP 依赖权威响应这一概念:由目标 URI 中标识的源服务器 (或在其指示下) 确定的响应, 根据生成响应消息时目标资源的状态,该响应被认为最适合该请求 。

当 authority 组件中使用注册名称时,“http”URI 方案 (第 4.2.1 节) 依赖用户的 本地名称解析服务来确定在哪里可以找到权威响应 。这意味着任何针对用户网络主机表、缓存名称或名称 解析库的攻击,都会成为攻击“http” URI 权威性建立过程的途径。同样,用户选择的域名服务 (DNS) 服务器,以及 获取解析结果的服务器层次结构,都可能影响 地址映射的真实性;DNS 安全扩展 (DNSSEC, [RFC4033]) 是提高 真实性的一种方式,通过更安全传输协议发出 DNS 请求的各种机制也是如此 。

此外,获得 IP 地址后,为“http”URI 建立权威性仍 容易受到 Internet 协议路由攻击。

“https”方案 (第 4.2.2 节) 旨在 防止 (或至少揭示) 对建立权威性的许多潜在攻击, 前提是协商的连接受到保护,并且客户端正确 验证通信服务器的身份与目标 URI 的 authority 组件匹配 (第 4.3.4 节)。正确实现此类验证可能很困难 (参见 [Georgiev])。

给定源服务器的权威性可以通过协议扩展委托;例如 [ALTSVC]。同样,可被视为某条连接权威方的 服务器集合可以通过诸如 [RFC8336]之类的协议扩展进行更改。

由非权威来源 (例如共享代理缓存) 提供响应, 通常有助于提高性能和可用性,但仅限于 该来源可信,或不可信响应可以安全使用的程度。

遗憾的是,向用户传达权威性可能很困难。例如, 网络钓鱼是一种针对用户权威性感知的攻击,这种 感知可能通过在超文本中展示相似品牌而被误导,可能还借助 userinfo 混淆 authority 组件 (参见 第 4.2.1 节)。用户代理可以通过让用户在执行 操作之前轻松检查目标 URI,在存在 userinfo 时显著区分 (或拒绝) 它,以及在引用文档来自未知或 不受信任来源时不发送已存储的凭据和 Cookie,来减轻 网络钓鱼攻击的影响。

17.2. 中间方的风险

HTTP 中间方天然处于可进行路径上攻击的位置。运行 中间方的系统一旦被攻破,可能导致严重的安全和隐私 问题。中间方可能接触安全相关信息、个人 用户和组织的个人信息,以及 属于用户和内容提供者的专有信息。被攻破的中间方,或者 未考虑安全和隐私因素而实现或配置的中间方,可能 被用于实施各种潜在攻击。

包含共享缓存的中间方尤其容易受到缓存投毒 攻击,如 [CACHING] 的第 7 节所述。

实现者需要考虑其设计和 编码决策以及提供给操作者的配置选项 (尤其是 默认配置) 所带来的隐私和安全影响。

中间方的可信程度不会高于其运行所依据的人员和策略; HTTP 无法解决此问题。

17.3. 基于文件和路径名称的攻击

源服务器经常使用其本地文件系统来管理从 目标 URI 到资源表示的映射。大多数文件系统并非为防御 恶意文件或路径名称而设计。因此,源服务器在将目标 资源映射到文件、文件夹或目录时,需要避免 访问对系统具有特殊意义的名称。

例如,UNIX、Microsoft Windows 和其他操作系统使用 ".." 作为路径 组件来表示当前目录上一级目录,并使用特殊命名的路径或文件名 向系统设备发送数据。其他类型的存储系统中 可能存在类似命名约定。同样,本地存储系统在处理无效或 意外字符、分解字符的重新组合以及不区分大小写名称的大小写规范化时 ,往往令人头疼地偏向用户友好性而不是安全性。

基于此类特殊名称的攻击往往集中于拒绝服务 (例如, 让服务器从 COM 端口读取数据),或泄露本不应提供的配置和源 文件。

17.4. 基于命令、代码或查询注入的攻击

源服务器经常使用 URI 中的参数作为标识系统 服务、选择数据库条目或选择数据源的方式。但是,请求中收到的数据 不能被信任。攻击者可以构造任何请求数据 元素 (方法、目标 URI、头字段或内容),使其包含在通过命令调用、 语言解释器或数据库接口传递时可能被 误解为命令、代码或查询的数据。

例如,SQL 注入是一种常见攻击,其中附加查询语言被 插入目标 URI 或头字段的某个部分 (例如 Host、Referer 等)。如果收到的数据直接用于 SELECT 语句,查询语言可能被解释为数据库命令,而不是 简单字符串值。尽管很容易防止,这类实现漏洞却极其常见 。

一般而言,资源实现应当避免在会被 处理或解释为指令的上下文中使用请求数据。参数应当与固定 字符串比较,并根据比较结果采取操作,而不是通过 未准备好处理不可信数据的接口传递。不基于 固定参数的收到数据应当仔细过滤或编码,以避免被 误解。

类似考虑也适用于请求数据被存储并随后处理的情况,例如 日志文件、监控工具中,或被包含在允许 嵌入脚本的数据格式中时。

17.5. 通过协议元素长度进行的攻击

由于 HTTP 大多使用文本、字符分隔的字段,解析器通常 容易受到通过发送非常长 (或非常慢) 的数据流进行的攻击, 尤其是在实现预期协议元素没有预定义 长度时 (第 2.3 节)。

为了促进互操作性,对字段的最小大小限制给出了具体建议 (第 5.4 节)。这些是 最低建议,选择这些值是为了让资源有限的实现也能支持; 预期大多数实现会选择高得多的 限制。

服务器可以拒绝目标 URI 过长 (第 15.5.15 节) 或请求内容过大 (第 15.5.14 节) 的消息。 HTTP 扩展还定义了与容量限制相关的其他状态码 [RFC6585]。

接收方应当谨慎限制处理其他协议 元素的程度,包括 (但不限于) 请求方法、响应状态短语、字段 名称、数值和块长度。未限制这种处理可能导致 缓冲区或算术溢出引起任意代码执行,并增加 遭受拒绝服务攻击的脆弱性。

17.6. 使用共享字典压缩的攻击

某些针对加密协议的攻击利用动态 压缩造成的大小差异来泄露机密信息;例如 [BREACH]。这些攻击 依赖于在攻击者控制的内容和机密 信息之间制造冗余,使得对两种内容使用同一字典的动态压缩算法 在攻击者控制的内容与 机密内容的部分匹配时压缩得更高效。

HTTP 消息可以通过多种方式压缩,包括使用 TLS 压缩、 内容编码、传输编码以及其他扩展或特定于版本的机制。

缓解此风险最有效的方法是对敏感数据禁用压缩, 或严格分离敏感数据和攻击者控制的数据,使它们无法 共享同一压缩字典。通过谨慎设计,压缩方案可以 被设计为在有限用例中不被认为可利用,例如 HPACK ([HPACK])。

17.7. 个人信息的披露

客户端通常掌握大量个人信息,包括 用户为与资源交互而提供的信息 (例如用户的姓名、 位置、邮件地址、密码、加密密钥等),以及 用户随时间推移的浏览活动信息 (例如历史记录、书签等)。实现 需要防止无意披露个人信息。

17.8. 服务器日志信息的隐私

服务器可以随时间保存有关用户请求的个人数据, 这些数据可能识别其阅读模式或感兴趣的主题。特别是,在中间方收集的日志 信息通常包含用户代理跨多个站点的 交互历史,可追溯到具体用户。

HTTP 日志信息本质上是机密的;其处理通常受法律 和法规约束。日志信息需要安全存储,并在分析时遵循适当指南 。对单个 条目中的个人信息进行匿名化有所帮助,但通常不足以防止真实日志轨迹根据与其他访问特征的关联而被 重新识别。因此,即使键是 假名化的,与特定客户端关联的访问轨迹也不适合公开。

为了最大限度降低被盗或意外发布的风险,日志信息应当 在不再需要支持安全、审计或欺诈控制等运营需求时,尽快清除个人可识别信息,包括用户标识符、IP 地址 和用户提供的查询参数 。

17.9. URI 中敏感信息的披露

URI 旨在共享,而不是保护,即使它们标识的是安全资源。 URI 经常显示在屏幕上,在打印页面时被添加到模板中,并存储 在各种不受保护的书签列表中。许多服务器、代理和用户代理会记录 或显示目标 URI,而这些位置可能被第三方看到。因此, 在 URI 中包含敏感、可识别个人身份或 泄露后有风险的信息是不明智的。

当应用程序使用客户端机制根据 用户提供的信息构造目标 URI,例如使用 GET 的表单查询字段时,可能 提供不适合在 URI 中披露的敏感数据 。在这种情况下通常首选 POST,因为它通常不会构造 URI; 相反,表单 POST 会在请求内容中传输潜在敏感数据。 但是,这会妨碍缓存,并为原本 安全的请求使用不安全方法。其他解决办法包括在构造 URI 之前转换用户提供的数据 ,或过滤数据,只包含不 敏感的常见值。同样,将查询结果重定向到不同的 (服务器生成的) URI,可以从后续链接中移除潜在敏感数据,并为以后复用提供可缓存 响应。

由于 Referer 头字段会告诉目标 站点导致请求产生的上下文,因此它可能泄露 用户最近的浏览历史以及引用资源 URI 中可能存在的任何个人信息 。为处理其中部分安全考虑,对 Referer 头 字段的限制在 第 10.1.3 节中描述。

17.10. 应用程序对字段名称的处理

服务器经常使用非 HTTP 网关接口和框架来处理收到的 请求并生成响应内容。由于历史原因,这类接口 通常将收到的字段名称作为外部变量名称传递,并使用适合环境变量的名称映射 。

例如,由 [RFC3875] 的第 4.1.18 节定义的通用网关接口 (CGI) 的协议特定 元变量映射, 会应用于与 CGI 标准 变量之一不对应的已接收头字段;该映射包括在每个名称前加上 "HTTP_" 并将所有 连字符 ("-") 实例改为下划线 ("_")。为了简化应用程序从一个 平台迁移到另一个平台, 许多其他应用程序框架继承了相同的映射。

在 CGI 中,收到的 Content-Length 字段 会作为元变量 "CONTENT_LENGTH" 传递,其字符串值与 收到的字段值匹配。相比之下,收到的 "Content_Length" 头字段会 作为协议特定元变量 "HTTP_CONTENT_LENGTH" 传递,如果应用程序错误读取协议特定元变量 而不是默认元变量,则可能导致 某些混淆。(这种历史惯例就是 第 16.3.2.1 节不鼓励 创建包含下划线的新字段名称的原因。)

遗憾的是,如果映射不完整或含糊,将字段名称映射到不同接口名称可能导致安全 漏洞。例如,如果攻击者 发送名为 "Transfer_Encoding" 的字段,一个朴素接口可能将其映射为 与 "Transfer-Encoding" 字段相同的变量名称,从而导致潜在的请求 走私漏洞 ([HTTP/1.1] 的第 11.2 节)。

为了缓解相关风险,执行此类映射的实现应当 使映射对于作为名称接收的全部潜在八位字节范围 都明确且完整 (包括 HTTP 语法不鼓励或禁止的字符)。例如,具有异常名称字符的字段可能导致 请求被阻止、特定字段被移除,或名称使用 不同前缀传递以与其他字段区分。

17.11. 重定向后片段的披露

尽管 URI 引用中使用的片段标识符不会在请求中发送, 实现者应当意识到,它们对用户代理以及因响应而运行的任何 扩展或脚本都是可见的。特别是,当发生 重定向,并且原始请求的片段标识符被 Location 中的新 引用继承时 (第 10.2.2 节),这可能导致一个站点的片段披露给另一个 站点。如果第一个站点在片段中使用个人信息,它应当确保 重定向到其他站点时包含一个 (可能为空的) 片段组件,以阻止 这种继承。

17.12. 产品信息的披露

User-Agent (第 10.1.5 节)、Via (第 7.6.3 节) 和 Server (第 10.2.4 节) 头字段通常 会泄露有关相应发送方软件系统的信息。理论上,这会 使攻击者更容易利用已知安全漏洞;实际中,攻击者 往往会尝试所有潜在漏洞,而不管表面上正在使用什么软件版本 。

充当网络防火墙门户的代理应当特别 谨慎传输可能标识防火墙后主机的头信息 。Via 头字段允许 中间方用假名替换敏感的机器名称。

17.13. 浏览器指纹识别

浏览器指纹识别是一组通过用户代理独特的特征集合随时间识别特定用户代理的技术 。这些特征可能包括 与它如何使用底层传输协议、功能 能力和脚本环境有关的信息,不过这里特别关注的是可能通过 HTTP 传达的独特特征集合 。指纹识别被 视为隐私问题,因为它使人能够随时间跟踪用户代理的行为 ([Bujlow]), 却没有用户可能对其他形式的数据 收集 (例如 Cookie) 拥有的相应控制。许多通用用户代理 (即 Web 浏览器) 已经 采取措施减少其指纹。

有许多请求头字段可能向服务器泄露足够独特的信息, 从而实现指纹识别。From 头字段最明显,不过预计 From 只会在用户希望自我标识时发送。同样,Cookie 头字段被特意设计为允许重新识别,因此指纹识别 问题只适用于用户代理配置禁用或限制 Cookie 的情况 。

User-Agent 头字段可能包含 足以唯一识别特定设备的信息,通常是在与 其他特征结合时,尤其当用户代理发送有关 用户系统或扩展的过多细节时。但是,用户最意想不到的 独特信息来源是主动 协商 (第 12.1 节),包括 Accept、Accept-Charset、Accept-Encoding 和 Accept-Language 头字段。

除了指纹识别问题外,详细使用 Accept-Language 头字段可能 泄露用户认为属于隐私性质的信息。例如, 理解某个给定语言集合可能与属于某个 特定族群高度相关。一种限制这种隐私损失的方法,是让 用户代理除非对明确允许的站点,否则省略发送 Accept-Language, 也许是在检测到表明语言协商可能有用的 Vary 头字段后通过交互获得许可。

在使用代理增强隐私的环境中,用户代理发送主动协商头字段时应当 保守。提供高度头字段可配置性的通用用户代理 应当告知用户,如果提供过多细节可能导致的隐私损失 。作为一种极端隐私措施,代理可以过滤中继 请求中的主动协商头字段。

17.14. 验证器保留

本规范定义的验证器并非旨在确保 表示的有效性、防范恶意更改或检测路径上攻击。最好情况下, 当所有参与者都行为良好时,它们可以实现更高效的缓存更新和乐观并发写入 。最坏情况下,条件会失败,客户端将 收到与没有条件 请求的 HTTP 交换相比不会造成更大危害的响应。

实体标签可以被滥用,从而产生隐私风险。例如,站点可能 故意构造一个语义无效、对用户或 用户代理唯一的实体标签,在具有很长新鲜度时间的可缓存响应中发送它,然后在 后续条件请求中读取该实体标签,作为重新识别该用户或 用户代理的手段。只要用户代理保留原始缓存条目,这种识别标签就会成为持久标识符 。缓存表示的用户代理 应当确保每当用户执行维护 隐私的操作 (例如清除已存储 Cookie 或切换到私密 浏览模式) 时清除或替换缓存。

17.15. 使用 Range 的拒绝服务攻击

不受约束的多范围请求容易受到拒绝服务攻击, 因为请求同一数据的许多重叠范围所需的工作量很小 ,相比之下,尝试以许多部分提供所请求数据会消耗大量时间、内存和带宽 。服务器应当忽略、合并或拒绝过分的 范围请求,例如请求两个以上重叠范围,或在单个集合中请求许多小 范围,尤其是在没有明显原因却乱序请求范围时 。多部分范围请求并非设计用于支持随机访问。

17.16. 身份验证注意事项

HTTP 身份验证主题的一切都是安全考虑,因此下面的 注意事项列表并不详尽。此外,它仅限于一般身份验证框架的安全 考虑,而不是 讨论特定身份验证方案的所有潜在考虑 (这些应当记录在定义相应方案的规范中)。多个 组织维护 Web 应用程序安全主题信息和当前研究链接 (例如 [OWASP]),包括 实际中实现和使用身份验证方案时的常见陷阱。

17.16.1. 凭据的机密性

HTTP 身份验证框架没有定义单一机制来维护 凭据的机密性;相反,每种身份验证方案都定义 凭据在传输前如何编码。虽然这为未来身份验证方案的开发提供了灵活性 ,但对于保护 本身不提供机密性或不能充分防止重放攻击的现有方案来说,这是不够的 。此外,如果服务器 期望每个单独用户都有特定凭据,那么这些 凭据的交换会起到识别该用户的作用,即使凭据中的内容 仍保持机密。

HTTP 依赖底层传输层或会话层 连接的安全属性来提供字段的机密传输。依赖 单个用户身份验证的服务需要在交换凭据之前建立受保护的连接 (第 4.2.2 节)。

17.16.2. 凭据和空闲客户端

现有 HTTP 客户端和用户代理通常无限期保留身份验证信息 。HTTP 没有提供让源服务器指示 客户端丢弃这些缓存凭据的机制,因为协议并不知道 用户代理如何获取或管理凭据。使凭据 过期或撤销的机制可以作为身份验证 方案定义的一部分指定。

凭据缓存可能干扰应用程序 安全模型的情况包括但不限于:

  • 客户端长时间处于空闲状态,之后服务器 可能希望让客户端重新提示用户输入凭据。
  • 包含会话终止指示的应用程序 (例如页面上的 "logout" 或 "commit" 按钮),在此之后应用程序服务器端 “知道”客户端没有进一步理由保留 凭据。

鼓励缓存凭据的用户代理提供一个用户可控制且易于访问的 机制,用于丢弃缓存凭据。

17.16.3. 保护空间

仅依赖 "realm" 机制建立 保护空间的身份验证方案,会将凭据暴露给源服务器上的所有资源。 已成功向某资源发出已验证请求的客户端,可以对同一源服务器上的其他资源使用 相同身份验证凭据。 这使得不同资源有可能收集其他资源的身份验证 凭据。

当一个源服务器在同一源下为多个 参与方托管资源时,这一点尤其值得关注 (第 11.5 节)。可能的 缓解策略包括限制对身份验证 凭据的直接访问 (即不提供 Authorization 请求头字段的内容),以及 通过为每个参与方使用不同主机名 (或端口号) 来分隔 保护空间。

17.16.4. 附加响应字段

向通过未加密信道发送的响应添加信息可能影响 安全和隐私。仅 Authentication-Info 和 Proxy-Authentication-Info 头字段的存在就表明 正在使用 HTTP 身份验证。身份验证方案特定参数的内容可能 暴露附加信息;在定义这些方案时必须 考虑这一点。

18. IANA 注意事项

以下注册的变更控制者是:"IETF (iesg@ietf.org) - Internet 工程任务组"。

18.1. URI 方案注册

IANA 已更新位于 [BCP35] 的“统一资源标识符 (URI) 方案”注册表 https://www.iana.org/assignments/uri-schemes/ ,加入了 第 4.2 节中 表 2列出的永久方案。

18.2. 方法注册

IANA 已更新位于 https://www.iana.org/assignments/http-methods 的“超文本传输协议 (HTTP) 方法注册表”,加入了 第 16.1.1 节的注册程序以及下表概括的 方法名称。

表 7
方法 安全 幂等 章节
CONNECT no no 9.3.6
DELETE no yes 9.3.5
GET yes yes 9.3.1
HEAD yes yes 9.3.2
OPTIONS yes yes 9.3.7
POST no no 9.3.3
PUT no yes 9.3.4
TRACE yes yes 9.3.8
* no no 18.2

方法名称 "*" 被保留,因为使用 "*" 作为 方法名称会与它在某些字段中作为通配符的用法冲突 (例如 "Access-Control-Request-Method")。

18.3. 状态码注册

IANA 已更新位于 https://www.iana.org/assignments/http-status-codes 的“超文本传输协议 (HTTP) 状态码注册表”,加入了 第 16.2.1 节的注册程序以及 下表概括的状态码值。

表 8
值 描述 章节
100 继续 15.2.1
101 切换协议 15.2.2
200 OK 15.3.1
201 已创建 15.3.2
202 已接受 15.3.3
203 非权威信息 15.3.4
204 无内容 15.3.5
205 重置内容 15.3.6
206 部分内容 15.3.7
300 多种选择 15.4.1
301 永久移动 15.4.2
302 找到 15.4.3
303 查看其他 15.4.4
304 未修改 15.4.5
305 使用代理 15.4.6
306 (未使用) 15.4.7
307 临时重定向 15.4.8
308 永久重定向 15.4.9
400 错误请求 15.5.1
401 未授权 15.5.2
402 需要付款 15.5.3
403 禁止 15.5.4
404 未找到 15.5.5
405 方法不允许 15.5.6
406 不可接受 15.5.7
407 需要代理身份验证 15.5.8
408 请求超时 15.5.9
409 冲突 15.5.10
410 已消失 15.5.11
411 需要长度 15.5.12
412 前置条件失败 15.5.13
413 内容过大 15.5.14
414 URI 过长 15.5.15
415 不支持的媒体类型 15.5.16
416 范围不可满足 15.5.17
417 期望失败 15.5.18
418 (未使用) 15.5.19
421 错误定向的请求 15.5.20
422 无法处理的内容 15.5.21
426 需要升级 15.5.22
500 内部服务器错误 15.6.1
501 未实现 15.6.2
502 错误网关 15.6.3
503 服务不可用 15.6.4
504 网关超时 15.6.5
505 不支持的 HTTP 版本 15.6.6

18.4. 字段名称注册

本规范更新 [RFC3864]定义的现有消息头字段注册 程序中与 HTTP 相关的部分 。它通过定义新的注册 程序并将 HTTP 字段定义移入单独的注册表,取代与 HTTP 有关的旧程序。

IANA 已创建名为“超文本传输协议 (HTTP) 字段名称 注册表”的新注册表,如 第 16.3.1 节所述。

IANA 已将“永久消息头字段名称”和“临时 消息头字段名称”注册表中 (参见 https://www.iana.org/assignments/message-headers/) 协议为 'http' 的所有条目移至此注册表,并应用以下更改:

  1. 'Applicable Protocol' 字段已省略。
  2. 状态为 'standard'、'experimental'、'reserved' 或 'informational' 的条目已改为状态 'permanent'。
  3. 没有状态的 provisional 条目已改为状态 'provisional'。
  4. 没有状态的 permanent 条目 (在确认注册 文档未定义状态之后) 已改为状态 'provisional'。 如果有证据表明另一状态更适当,专家可以选择更新条目的状态 。

IANA 已在“永久消息头字段名称”和“临时消息 头字段名称”注册表中添加以下注释,以指示 HTTP 字段名称 注册已移动:

IANA 已更新“超文本传输协议 (HTTP) 字段名称注册表”,加入 下表列出的字段名称。

表 9
字段名称 状态 章节 注释
Accept permanent 12.5.1
Accept-Charset deprecated 12.5.2
Accept-Encoding permanent 12.5.3
Accept-Language permanent 12.5.4
Accept-Ranges permanent 14.3
Allow permanent 10.2.1
Authentication-Info permanent 11.6.3
Authorization permanent 11.6.2
Connection permanent 7.6.1
Content-Encoding permanent 8.4
Content-Language permanent 8.5
Content-Length permanent 8.6
Content-Location permanent 8.7
Content-Range permanent 14.4
Content-Type permanent 8.3
Date permanent 6.6.1
ETag permanent 8.8.3
Expect permanent 10.1.1
From permanent 10.1.2
Host permanent 7.2
If-Match permanent 13.1.1
If-Modified-Since permanent 13.1.3
If-None-Match permanent 13.1.2
If-Range permanent 13.1.5
If-Unmodified-Since permanent 13.1.4
Last-Modified permanent 8.8.2
Location permanent 10.2.2
Max-Forwards permanent 7.6.2
Proxy-Authenticate permanent 11.7.1
Proxy-Authentication-Info permanent 11.7.3
Proxy-Authorization permanent 11.7.2
Range permanent 14.2
Referer permanent 10.1.3
Retry-After permanent 10.2.3
Server permanent 10.2.4
TE permanent 10.1.4
Trailer permanent 6.6.2
Upgrade permanent 7.8
User-Agent permanent 10.1.5
Vary permanent 12.5.5
Via permanent 7.6.3
WWW-Authenticate permanent 11.6.1
* permanent 12.5.5 (保留)

字段名称 "*" 被保留,因为 使用该名称作为 HTTP 头字段可能与它在 Vary 头字段中的特殊语义冲突 (第 12.5.5 节)。

IANA 已更新新 注册表中的 "Content-MD5" 条目,将其状态设为 'obsoleted',并引用 [RFC2616] 的第 14.15 节 (用于 头字段定义) 以及 [RFC7231] 的附录 B (其中从更新后的规范中移除了该字段定义)。

18.5. 身份验证方案注册

IANA 已更新“超文本传输协议 (HTTP) 身份验证方案注册表” ,位于 https://www.iana.org/assignments/http-authschemes ,加入了 第 16.4.1 节的注册程序。本文未定义 任何身份验证方案。

18.6. 内容编码注册

IANA 已更新位于 https://www.iana.org/assignments/http-parameters/ 的“HTTP 内容编码注册表”,加入了 第 16.6.1 节的注册程序以及下表 概括的内容编码名称。

表 10
名称 描述 章节
compress UNIX "compress" 数据格式 [Welch] 8.4.1.1
deflate "zlib" 数据格式 ([RFC1950]) 中的 "deflate" 压缩数据 ([RFC1951]) 8.4.1.2
gzip GZIP 文件格式 [RFC1952] 8.4.1.3
identity 保留 12.5.3
x-compress 已弃用 (compress 的别名) 8.4.1.1
x-gzip 已弃用 (gzip 的别名) 8.4.1.3

18.7. 范围单位注册

IANA 已更新位于 https://www.iana.org/assignments/http-parameters/ 的“HTTP 范围单位注册表”,加入了 第 16.5.1 节的注册程序以及下表概括的 范围单位名称。

表 11
范围单位名称 描述 章节
bytes 八位字节范围 14.1.2
none 保留为表示不支持范围请求的关键词 14.3

18.8. 媒体类型注册

IANA 已更新位于 https://www.iana.org/assignments/media-types 的“媒体类型”注册表,加入了 第 14.6 节中媒体类型 "multipart/byteranges" 的注册信息。

IANA 已更新关于 "q" 参数的注册表注释,并添加指向本文 第 12.5.1 节 的链接。

18.9. 端口 注册

IANA 已更新位于 https://www.iana.org/assignments/service-names-port-numbers/ 的“服务名称和传输协议端口号注册表”,针对使用 UDP 或 TCP 的端口 80 和 443 上的服务:

  1. 使用本文作为 "Reference",并且
  2. 当前未指定时,将 "Assignee" 设为 "IESG",将 "Contact" 设为 "IETF_Chair"。

18.10. Upgrade 令牌注册

IANA 已更新位于 https://www.iana.org/assignments/http-upgrade-tokens 的“超文本传输协议 (HTTP) Upgrade 令牌注册表”,加入了 第 16.7 节所述的注册程序以及下表 概括的 upgrade 令牌名称。

表 12
名称 描述 预期版本令牌 章节
HTTP 超文本传输协议 任意 DIGIT.DIGIT (例如 "2.0") 2.5

19. 参考文献

19.1. 规范性参考文献

[CACHING]
Fielding, R., 编, Nottingham, M., 编, 和 J. Reschke, 编, “HTTP 缓存”, STD 98, RFC 9111, DOI 10.17487/RFC9111, 2022 年 6 月。
[RFC1950]
Deutsch, P. 和 J-L. Gailly, “ZLIB 压缩数据格式 规范 3.3 版”, RFC 1950, DOI 10.17487/RFC1950, 1996 年 5 月, <https://www.rfc-editor.org/info/rfc1950>。
[RFC1951]
Deutsch, P., “DEFLATE 压缩数据格式规范 1.3 版”, RFC 1951, DOI 10.17487/RFC1951, 1996 年 5 月, <https://www.rfc-editor.org/info/rfc1951>。
[RFC1952]
Deutsch, P., “GZIP 文件格式 规范 4.3 版”, RFC 1952, DOI 10.17487/RFC1952, 1996 年 5 月, <https://www.rfc-editor.org/info/rfc1952>。
[RFC2046]
Freed, N. 和 N. Borenstein, “多用途 Internet 邮件 扩展 (MIME) 第二部分:媒体类型”, RFC 2046, DOI 10.17487/RFC2046, 1996 年 11 月 , <https://www.rfc-editor.org/info/rfc2046>。
[RFC2119]
Bradner, S., “用于 RFC 中表示要求级别的关键词”, BCP 14, RFC 2119, DOI 10.17487/RFC2119, 1997 年 3 月, <https://www.rfc-editor.org/info/rfc2119>。
[RFC4647]
Phillips, A., 编 和 M. Davis, 编, “语言 标签匹配”, BCP 47, RFC 4647, DOI 10.17487/RFC4647, 2006 年 9 月 , <https://www.rfc-editor.org/info/rfc4647>。
[RFC4648]
Josefsson, S., “Base16、 Base32 和 Base64 数据编码”, RFC 4648, DOI 10.17487/RFC4648, 2006 年 10 月 , <https://www.rfc-editor.org/info/rfc4648>。
[RFC5234]
Crocker, D., 编 和 P. Overell, “语法 规范的扩充 BNF:ABNF”, STD 68, RFC 5234, DOI 10.17487/RFC5234, 2008 年 1 月, <https://www.rfc-editor.org/info/rfc5234>。
[RFC5280]
Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., 和 W. Polk, “Internet X.509 公钥 基础设施证书和证书撤销列表 (CRL) 配置文件”, RFC 5280, DOI 10.17487/RFC5280, 2008 年 5 月, <https://www.rfc-editor.org/info/rfc5280>。
[RFC5322]
Resnick, P., 编, “Internet 消息格式”, RFC 5322, DOI 10.17487/RFC5322, 2008 年 10 月, <https://www.rfc-editor.org/info/rfc5322>。
[RFC5646]
Phillips, A., 编 和 M. Davis, 编, “标识 语言的标签”, BCP 47, RFC 5646, DOI 10.17487/RFC5646, 2009 年 9 月, <https://www.rfc-editor.org/info/rfc5646>。
[RFC6125]
Saint-Andre, P. 和 J. Hodges, “在传输 层安全性 (TLS) 上下文中使用 X.509 (PKIX) 证书表示和验证基于域的应用服务 身份”, RFC 6125, DOI 10.17487/RFC6125, 2011 年 3 月, <https://www.rfc-editor.org/info/rfc6125>。
[RFC6365]
Hoffman, P. 和 J. Klensin, “IETF 国际化中使用的 术语”, BCP 166, RFC 6365, DOI 10.17487/RFC6365, 2011 年 9 月 , <https://www.rfc-editor.org/info/rfc6365>。
[RFC7405]
Kyzivat, P., “ABNF 中对区分大小写 字符串的支持”, RFC 7405, DOI 10.17487/RFC7405, 2014 年 12 月 , <https://www.rfc-editor.org/info/rfc7405>。
[RFC8174]
Leiba, B., “RFC 2119 关键词 大写与小写的歧义”, BCP 14, RFC 8174, DOI 10.17487/RFC8174, 2017 年 5 月, <https://www.rfc-editor.org/info/rfc8174>。
[TCP]
Postel, J., “传输 控制协议”, STD 7, RFC 793, DOI 10.17487/RFC0793, 1981 年 9 月, <https://www.rfc-editor.org/info/rfc793>。
[TLS13]
Rescorla, E., “传输 层安全性 (TLS) 协议 1.3 版”, RFC 8446, DOI 10.17487/RFC8446, 2018 年 8 月 , <https://www.rfc-editor.org/info/rfc8446>。
[URI]
Berners-Lee, T., Fielding, R., 和 L. Masinter, “统一资源标识符 (URI):通用语法”, STD 66, RFC 3986, DOI 10.17487/RFC3986, 2005 年 1 月, <https://www.rfc-editor.org/info/rfc3986>。
[USASCII]
美国国家标准协会, “编码字符集 -- 7 位美国 信息交换标准代码”, ANSI X3.4, 1986。
[Welch]
Welch, T., “一种 高性能数据压缩技术”, IEEE Computer 17(6), DOI 10.1109/MC.1984.1659158, 1984 年 6 月, <https://ieeexplore.ieee.org/document/1659158/>。

19.2. 资料性参考文献

[ALTSVC]
Nottingham, M., McManus, P., 和 J. Reschke, “HTTP 替代 服务”, RFC 7838, DOI 10.17487/RFC7838, 2016 年 4 月, <https://www.rfc-editor.org/info/rfc7838>。
[BCP13]
Freed, N. 和 J. Klensin, “多用途 Internet 邮件 扩展 (MIME) 第四部分:注册程序”, BCP 13, RFC 4289, DOI 10.17487/RFC4289, 2005 年 12 月 。
Freed, N., Klensin, J., 和 T. Hansen, “媒体类型规范和 注册程序”, BCP 13, RFC 6838, DOI 10.17487/RFC6838, 2013 年 1 月 。
<https://www.rfc-editor.org/info/bcp13>
[BCP178]
Saint-Andre, P., Crocker, D., 和 M. Nottingham, “弃用应用协议中的 "X-" 前缀 和类似构造”, BCP 178, RFC 6648, DOI 10.17487/RFC6648, 2012 年 6 月。
<https://www.rfc-editor.org/info/bcp178>
[BCP35]
Thaler, D., 编, Hansen, T., 和 T. Hardie, “URI 方案指南和注册 程序”, BCP 35, RFC 7595, DOI 10.17487/RFC7595, 2015 年 6 月。
<https://www.rfc-editor.org/info/bcp35>
[BREACH]
Gluck, Y., Harris, N., 和 A. Prado, “BREACH: 复活 CRIME 攻击”, 2013 年 7 月, <http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf>。
[Bujlow]
Bujlow, T., Carela-Español, V., Solé-Pareta, J., 和 P. Barlet-Ros, “Web 跟踪综述:机制、影响和防御”, DOI 10.1109/JPROC.2016.2637878, 载于 IEEE Proceedings 105(8), 2017 年 8 月。
Barth, A., “HTTP 状态 管理机制”, RFC 6265, DOI 10.17487/RFC6265, 2011 年 4 月, <https://www.rfc-editor.org/info/rfc6265>。
[Err1912]
RFC 勘误, 勘误 ID 1912, RFC 2978, <https://www.rfc-editor.org/errata/eid1912>。
[Err5433]
RFC 勘误, 勘误 ID 5433, RFC 2978, <https://www.rfc-editor.org/errata/eid5433>。
[Georgiev]
Georgiev, M., Iyengar, S., Jana, S., Anubhai, R., Boneh, D., 和 V. Shmatikov, “世界上 最危险的代码:在非浏览器 软件中验证 SSL 证书”, DOI 10.1145/2382196.2382204, 载于 2012 ACM 计算机与通信安全会议 (CCS '12), 第 38-49 页, 2012 年 10 月。
[HPACK]
Peon, R. 和 H. Ruellan, “HPACK:HTTP/2 的头部压缩 ”, RFC 7541, DOI 10.17487/RFC7541, 2015 年 5 月, <https://www.rfc-editor.org/info/rfc7541>。
[HTTP/1.0]
Berners-Lee, T., Fielding, R., 和 H. Frystyk, “超文本传输协议 -- HTTP/1.0”, RFC 1945, DOI 10.17487/RFC1945, 1996 年 5 月, <https://www.rfc-editor.org/info/rfc1945>。
[HTTP/1.1]
Fielding, R., 编, Nottingham, M., 编, 和 J. Reschke, 编, “HTTP/1.1”, STD 99, RFC 9112, DOI 10.17487/RFC9112, 2022 年 6 月。
[HTTP/2]
Thomson, M., 编 和 C. Benfield, 编, “HTTP/2”, RFC 9113, DOI 10.17487/RFC9113, 2022 年 6 月, <https://www.rfc-editor.org/info/rfc9113>。
[HTTP/3]
Bishop, M., 编, “HTTP/3”, RFC 9114, DOI 10.17487/RFC9114, 2022 年 6 月, <https://www.rfc-editor.org/info/rfc9114>。
[ISO-8859-1]
国际标准化组织, “信息技术 -- 8 位 单字节编码图形字符集 -- 第 1 部分:拉丁字母第 1 号”, ISO/IEC 8859-1:1998, 1998。
[Kri2001]
Kristol, D., “HTTP Cookie:标准、 隐私和政治”, ACM Internet 技术汇刊 1(2), 2001 年 11 月, <http://arxiv.org/abs/cs.SE/0105018>。
[OWASP]
开放 Web 应用程序安全项目, <https://www.owasp.org/>。
[REST]
Fielding, R., “架构风格和 基于网络的软件架构设计”, 博士学位论文, 加利福尼亚大学欧文分校, 2000 年 9 月, <https://roy.gbiv.com/pubs/dissertation/top.htm>。
[RFC1919]
Chatel, M., “传统与 透明 IP 代理”, RFC 1919, DOI 10.17487/RFC1919, 1996 年 3 月, <https://www.rfc-editor.org/info/rfc1919>。
[RFC2047]
Moore, K., “MIME (多用途 Internet 邮件扩展) 第三部分:非 ASCII 文本的消息头扩展”, RFC 2047, DOI 10.17487/RFC2047, 1996 年 11 月, <https://www.rfc-editor.org/info/rfc2047>。
[RFC2068]
Fielding, R., Gettys, J., Mogul, J., Frystyk, H., 和 T. Berners-Lee, “超文本传输协议 -- HTTP/1.1”, RFC 2068, DOI 10.17487/RFC2068, 1997 年 1 月, <https://www.rfc-editor.org/info/rfc2068>。
[RFC2145]
Mogul, J., Fielding, R., Gettys, J., 和 H. Frystyk, “HTTP 版本号的使用和解释 ”, RFC 2145, DOI 10.17487/RFC2145, 1997 年 5 月, <https://www.rfc-editor.org/info/rfc2145>。
[RFC2295]
Holtman, K. 和 A. Mutz, “HTTP 中的透明内容 协商”, RFC 2295, DOI 10.17487/RFC2295, 1998 年 3 月, <https://www.rfc-editor.org/info/rfc2295>。
[RFC2324]
Masinter, L., “超文本 咖啡壶控制协议 (HTCPCP/1.0)”, RFC 2324, DOI 10.17487/RFC2324, 1998 年 4 月 1 日 , <https://www.rfc-editor.org/info/rfc2324>。
[RFC2557]
Palme, J., Hopmann, A., 和 N. Shelness, “聚合文档(如 HTML)的 MIME 封装 (MHTML)”, RFC 2557, DOI 10.17487/RFC2557, 1999 年 3 月, <https://www.rfc-editor.org/info/rfc2557>。
[RFC2616]
Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., 和 T. Berners-Lee, “超文本 传输协议 -- HTTP/1.1”, RFC 2616, DOI 10.17487/RFC2616, 1999 年 6 月, <https://www.rfc-editor.org/info/rfc2616>。
[RFC2617]
Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A., 和 L. Stewart, “HTTP 身份验证:Basic 和 Digest 访问身份验证”, RFC 2617, DOI 10.17487/RFC2617, 1999 年 6 月, <https://www.rfc-editor.org/info/rfc2617>。
[RFC2774]
Nielsen, H., Leach, P., 和 S. Lawrence, “HTTP 扩展 框架”, RFC 2774, DOI 10.17487/RFC2774, 2000 年 2 月, <https://www.rfc-editor.org/info/rfc2774>。
[RFC2818]
Rescorla, E., “基于 TLS 的 HTTP”, RFC 2818, DOI 10.17487/RFC2818, 2000 年 5 月, <https://www.rfc-editor.org/info/rfc2818>。
[RFC2978]
Freed, N. 和 J. Postel, “IANA 字符集注册程序”, BCP 19, RFC 2978, DOI 10.17487/RFC2978, 2000 年 10 月 , <https://www.rfc-editor.org/info/rfc2978>。
[RFC3040]
Cooper, I., Melve, I., 和 G. Tomlinson, “Internet Web 复制和 缓存分类”, RFC 3040, DOI 10.17487/RFC3040, 2001 年 1 月 , <https://www.rfc-editor.org/info/rfc3040>。
[RFC3864]
Klyne, G., Nottingham, M., 和 J. Mogul, “消息头字段的 注册程序”, BCP 90, RFC 3864, DOI 10.17487/RFC3864, 2004 年 9 月, <https://www.rfc-editor.org/info/rfc3864>。
[RFC3875]
Robinson, D. 和 K. Coar, “通用 网关接口 (CGI) 1.1 版”, RFC 3875, DOI 10.17487/RFC3875, 2004 年 10 月 , <https://www.rfc-editor.org/info/rfc3875>。
[RFC4033]
Arends, R., Austein, R., Larson, M., Massey, D., 和 S. Rose, “DNS 安全介绍和 要求”, RFC 4033, DOI 10.17487/RFC4033, 2005 年 3 月, <https://www.rfc-editor.org/info/rfc4033>。
[RFC4559]
Jaganathan, K., Zhu, L., 和 J. Brezak, “Microsoft Windows 中基于 SPNEGO 的 Kerberos 和 NTLM HTTP 身份验证”, RFC 4559, DOI 10.17487/RFC4559, 2006 年 6 月, <https://www.rfc-editor.org/info/rfc4559>。
[RFC5789]
Dusseault, L. 和 J. Snell, “HTTP 的 PATCH 方法”, RFC 5789, DOI 10.17487/RFC5789, 2010 年 3 月, <https://www.rfc-editor.org/info/rfc5789>。
[RFC5905]
Mills, D., Martin, J., 编, Burbank, J., 和 W. Kasch, “网络时间协议第 4 版:协议和算法规范”, RFC 5905, DOI 10.17487/RFC5905, 2010 年 6 月, <https://www.rfc-editor.org/info/rfc5905>。
[RFC6454]
Barth, A., “Web 源 概念”, RFC 6454, DOI 10.17487/RFC6454, 2011 年 12 月, <https://www.rfc-editor.org/info/rfc6454>。
[RFC6585]
Nottingham, M. 和 R. Fielding, “附加 HTTP 状态 码”, RFC 6585, DOI 10.17487/RFC6585, 2012 年 4 月, <https://www.rfc-editor.org/info/rfc6585>。
[RFC7230]
Fielding, R., 编 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):消息语法和路由”, RFC 7230, DOI 10.17487/RFC7230, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7230>。
[RFC7231]
Fielding, R., 编 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):语义和内容”, RFC 7231, DOI 10.17487/RFC7231, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7231>。
[RFC7232]
Fielding, R., 编 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):条件请求”, RFC 7232, DOI 10.17487/RFC7232, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7232>。
[RFC7233]
Fielding, R., 编, Lafon, Y., 编, 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):范围请求”, RFC 7233, DOI 10.17487/RFC7233, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7233>。
[RFC7234]
Fielding, R., 编, Nottingham, M., 编, 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):缓存”, RFC 7234, DOI 10.17487/RFC7234, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7234>。
[RFC7235]
Fielding, R., 编 和 J. Reschke, 编, “超文本传输协议 (HTTP/1.1):身份验证”, RFC 7235, DOI 10.17487/RFC7235, 2014 年 6 月, <https://www.rfc-editor.org/info/rfc7235>。
[RFC7538]
Reschke, J., “超文本 传输协议状态码 308(永久重定向)”, RFC 7538, DOI 10.17487/RFC7538, 2015 年 4 月, <https://www.rfc-editor.org/info/rfc7538>。
[RFC7540]
Belshe, M., Peon, R., 和 M. Thomson, 编, “超文本传输协议 第 2 版 (HTTP/2)”, RFC 7540, DOI 10.17487/RFC7540, 2015 年 5 月, <https://www.rfc-editor.org/info/rfc7540>。
[RFC7578]
Masinter, L., “从表单返回 值:multipart/form-data”, RFC 7578, DOI 10.17487/RFC7578, 2015 年 7 月, <https://www.rfc-editor.org/info/rfc7578>。
[RFC7615]
Reschke, J., “HTTP Authentication-Info 和 Proxy-Authentication-Info 响应头字段”, RFC 7615, DOI 10.17487/RFC7615, 2015 年 9 月, <https://www.rfc-editor.org/info/rfc7615>。
[RFC7616]
Shekh-Yusef, R., 编, Ahrens, D., 和 S. Bremer, “HTTP 摘要访问 身份验证”, RFC 7616, DOI 10.17487/RFC7616, 2015 年 9 月, <https://www.rfc-editor.org/info/rfc7616>。
[RFC7617]
Reschke, J., “'Basic' HTTP 身份验证方案”, RFC 7617, DOI 10.17487/RFC7617, 2015 年 9 月 , <https://www.rfc-editor.org/info/rfc7617>。
[RFC7694]
Reschke, J., “超文本 传输协议 (HTTP) 客户端发起的内容编码”, RFC 7694, DOI 10.17487/RFC7694, 2015 年 11 月 , <https://www.rfc-editor.org/info/rfc7694>。
[RFC8126]
Cotton, M., Leiba, B., 和 T. Narten, “RFC 中 IANA 注意事项章节编写 指南”, BCP 26, RFC 8126, DOI 10.17487/RFC8126, 2017 年 6 月, <https://www.rfc-editor.org/info/rfc8126>。
[RFC8187]
Reschke, J., “指示 HTTP 头字段参数的字符编码和语言”, RFC 8187, DOI 10.17487/RFC8187, 2017 年 9 月 , <https://www.rfc-editor.org/info/rfc8187>。
[RFC8246]
McManus, P., “HTTP 不可变 响应”, RFC 8246, DOI 10.17487/RFC8246, 2017 年 9 月, <https://www.rfc-editor.org/info/rfc8246>。
[RFC8288]
Nottingham, M., “Web 链接”, RFC 8288, DOI 10.17487/RFC8288, 2017 年 10 月, <https://www.rfc-editor.org/info/rfc8288>。
[RFC8336]
Nottingham, M. 和 E. Nygren, “ORIGIN HTTP/2 帧”, RFC 8336, DOI 10.17487/RFC8336, 2018 年 3 月, <https://www.rfc-editor.org/info/rfc8336>。
[RFC8615]
Nottingham, M., “众所周知的 统一资源标识符 (URI)”, RFC 8615, DOI 10.17487/RFC8615, 2019 年 5 月, <https://www.rfc-editor.org/info/rfc8615>。
[RFC8941]
Nottingham, M. 和 P-H. Kamp, “HTTP 的结构化字段值 ”, RFC 8941, DOI 10.17487/RFC8941, 2021 年 2 月, <https://www.rfc-editor.org/info/rfc8941>。
[Sniffing]
WHATWG, “MIME 嗅探”, <https://mimesniff.spec.whatwg.org>。
[WEBDAV]
Dusseault, L., 编, “用于 Web 分布式创作和版本控制 (WebDAV) 的 HTTP 扩展”, RFC 4918, DOI 10.17487/RFC4918, 2007 年 6 月, <https://www.rfc-editor.org/info/rfc4918>。

附录 A. 汇总 ABNF

在下面汇总的 ABNF 中,列表规则按照 第 5.6.1 节展开。

Accept = [ ( media-range [ weight ] ) *( OWS "," OWS ( media-range [
  weight ] ) ) ]
 Accept-Charset = [ ( ( token / "*" ) [ weight ] ) *( OWS "," OWS ( (
  token / "*" ) [ weight ] ) ) ]
 Accept-Encoding = [ ( codings [ weight ] ) *( OWS "," OWS ( codings [
  weight ] ) ) ]
 Accept-Language = [ ( language-range [ weight ] ) *( OWS "," OWS (
  language-range [ weight ] ) ) ]
 Accept-Ranges = acceptable-ranges
 Allow = [ method *( OWS "," OWS method ) ]
 Authentication-Info = [ auth-param *( OWS "," OWS auth-param ) ]
 Authorization = credentials

 BWS = OWS

 Connection = [ connection-option *( OWS "," OWS connection-option )
  ]
 Content-Encoding = [ content-coding *( OWS "," OWS content-coding )
  ]
 Content-Language = [ language-tag *( OWS "," OWS language-tag ) ]
 Content-Length = 1*DIGIT
 Content-Location = absolute-URI / partial-URI
 Content-Range = range-unit SP ( range-resp / unsatisfied-range )
 Content-Type = media-type

 Date = HTTP-date

 ETag = entity-tag
 Expect = [ expectation *( OWS "," OWS expectation ) ]

 From = mailbox

 GMT = %x47.4D.54 ; GMT

 HTTP-date = IMF-fixdate / obs-date
 Host = uri-host [ ":" port ]

 IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
 If-Match = "*" / [ entity-tag *( OWS "," OWS entity-tag ) ]
 If-Modified-Since = HTTP-date
 If-None-Match = "*" / [ entity-tag *( OWS "," OWS entity-tag ) ]
 If-Range = entity-tag / HTTP-date
 If-Unmodified-Since = HTTP-date

 Last-Modified = HTTP-date
 Location = URI-reference

 Max-Forwards = 1*DIGIT

 OWS = *( SP / HTAB )

 Proxy-Authenticate = [ challenge *( OWS "," OWS challenge ) ]
 Proxy-Authentication-Info = [ auth-param *( OWS "," OWS auth-param )
  ]
 Proxy-Authorization = credentials

 RWS = 1*( SP / HTAB )
 Range = ranges-specifier
 Referer = absolute-URI / partial-URI
 Retry-After = HTTP-date / delay-seconds

 Server = product *( RWS ( product / comment ) )

 TE = [ t-codings *( OWS "," OWS t-codings ) ]
 Trailer = [ field-name *( OWS "," OWS field-name ) ]

 URI-reference = <URI-reference, see [URI], Section 4.1>
 Upgrade = [ protocol *( OWS "," OWS protocol ) ]
 User-Agent = product *( RWS ( product / comment ) )

 Vary = [ ( "*" / field-name ) *( OWS "," OWS ( "*" / field-name ) )
  ]
 Via = [ ( received-protocol RWS received-by [ RWS comment ] ) *( OWS
  "," OWS ( received-protocol RWS received-by [ RWS comment ] ) ) ]

 WWW-Authenticate = [ challenge *( OWS "," OWS challenge ) ]

 absolute-URI = <absolute-URI, see [URI], Section 4.3>
 absolute-path = 1*( "/" segment )
 acceptable-ranges = range-unit *( OWS "," OWS range-unit )
 asctime-date = day-name SP date3 SP time-of-day SP year
 auth-param = token BWS "=" BWS ( token / quoted-string )
 auth-scheme = token
 authority = <authority, see [URI], Section 3.2>

 challenge = auth-scheme [ 1*SP ( token68 / [ auth-param *( OWS ","
  OWS auth-param ) ] ) ]
 codings = content-coding / "identity" / "*"
 comment = "(" *( ctext / quoted-pair / comment ) ")"
 complete-length = 1*DIGIT
 connection-option = token
 content-coding = token
 credentials = auth-scheme [ 1*SP ( token68 / [ auth-param *( OWS ","
  OWS auth-param ) ] ) ]
 ctext = HTAB / SP / %x21-27 ; '!'-'''
  / %x2A-5B ; '*'-'['
  / %x5D-7E ; ']'-'~'
  / obs-text

 date1 = day SP month SP year
 date2 = day "-" month "-" 2DIGIT
 date3 = month SP ( 2DIGIT / ( SP DIGIT ) )
 day = 2DIGIT
 day-name = %x4D.6F.6E ; Mon
  / %x54.75.65 ; Tue
  / %x57.65.64 ; Wed
  / %x54.68.75 ; Thu
  / %x46.72.69 ; Fri
  / %x53.61.74 ; Sat
  / %x53.75.6E ; Sun
 day-name-l = %x4D.6F.6E.64.61.79 ; Monday
  / %x54.75.65.73.64.61.79 ; Tuesday
  / %x57.65.64.6E.65.73.64.61.79 ; Wednesday
  / %x54.68.75.72.73.64.61.79 ; Thursday
  / %x46.72.69.64.61.79 ; Friday
  / %x53.61.74.75.72.64.61.79 ; Saturday
  / %x53.75.6E.64.61.79 ; Sunday
 delay-seconds = 1*DIGIT

 entity-tag = [ weak ] opaque-tag
 etagc = "!" / %x23-7E ; '#'-'~'
  / obs-text
 expectation = token [ "=" ( token / quoted-string ) parameters ]

 field-content = field-vchar [ 1*( SP / HTAB / field-vchar )
  field-vchar ]
 field-name = token
 field-value = *field-content
 field-vchar = VCHAR / obs-text
 first-pos = 1*DIGIT

 hour = 2DIGIT
 http-URI = "http://" authority path-abempty [ "?" query ]
 https-URI = "https://" authority path-abempty [ "?" query ]

 incl-range = first-pos "-" last-pos
 int-range = first-pos "-" [ last-pos ]

 language-range = <language-range, see [RFC4647], Section 2.1>
 language-tag = <Language-Tag, see [RFC5646], Section 2.1>
 last-pos = 1*DIGIT

 mailbox = <mailbox, see [RFC5322], Section 3.4>
 media-range = ( "*/*" / ( type "/*" ) / ( type "/" subtype ) )
  parameters
 media-type = type "/" subtype parameters
 method = token
 minute = 2DIGIT
 month = %x4A.61.6E ; Jan
  / %x46.65.62 ; Feb
  / %x4D.61.72 ; Mar
  / %x41.70.72 ; Apr
  / %x4D.61.79 ; May
  / %x4A.75.6E ; Jun
  / %x4A.75.6C ; Jul
  / %x41.75.67 ; Aug
  / %x53.65.70 ; Sep
  / %x4F.63.74 ; Oct
  / %x4E.6F.76 ; Nov
  / %x44.65.63 ; Dec

 obs-date = rfc850-date / asctime-date
 obs-text = %x80-FF
 opaque-tag = DQUOTE *etagc DQUOTE
 other-range = 1*( %x21-2B ; '!'-'+'
  / %x2D-7E ; '-'-'~'
  )

 parameter = parameter-name "=" parameter-value
 parameter-name = token
 parameter-value = ( token / quoted-string )
 parameters = *( OWS ";" OWS [ parameter ] )
 partial-URI = relative-part [ "?" query ]
 path-abempty = <path-abempty, see [URI], Section 3.3>
 port = <port, see [URI], Section 3.2.3>
 product = token [ "/" product-version ]
 product-version = token
 protocol = protocol-name [ "/" protocol-version ]
 protocol-name = token
 protocol-version = token
 pseudonym = token

 qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'['
  / %x5D-7E ; ']'-'~'
  / obs-text
 query = <query, see [URI], Section 3.4>
 quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
 quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
 qvalue = ( "0" [ "." *3DIGIT ] ) / ( "1" [ "." *3"0" ] )

 range-resp = incl-range "/" ( complete-length / "*" )
 range-set = range-spec *( OWS "," OWS range-spec )
 range-spec = int-range / suffix-range / other-range
 range-unit = token
 ranges-specifier = range-unit "=" range-set
 received-by = pseudonym [ ":" port ]
 received-protocol = [ protocol-name "/" ] protocol-version
 relative-part = <relative-part, see [URI], Section 4.2>
 rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT

 second = 2DIGIT
 segment = <segment, see [URI], Section 3.3>
 subtype = token
 suffix-length = 1*DIGIT
 suffix-range = "-" suffix-length

 t-codings = "trailers" / ( transfer-coding [ weight ] )
 tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
  "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
 time-of-day = hour ":" minute ":" second
 token = 1*tchar
 token68 = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" )
  *"="
 transfer-coding = token *( OWS ";" OWS transfer-parameter )
 transfer-parameter = token BWS "=" BWS ( token / quoted-string )
 type = token

 unsatisfied-range = "*/" complete-length
 uri-host = <host, see [URI], Section 3.2.2>

 weak = %x57.2F ; W/
 weight = OWS ";" OWS "q=" qvalue

 year = 4DIGIT
 

附录 B. 与先前 RFC 相比的更改

B.1. 与 RFC 2818 相比的更改

无。

B.2. 与 RFC 7230 相比的更改

介绍 HTTP 设计目标、历史、架构、一致性 标准、协议版本控制、URI、消息路由和头字段的章节已移至 此处。

关于语义一致性的要求已替换为允许忽略或 规避特定于实现的故障。(第 2.2 节)

关于源以及对源服务器进行权威访问的说明已经扩展 到 "http" 和 "https" URI,以涵盖替代服务和不 一定基于 TCP 的受保护连接。(第 4.2.1、4.2.2、4.3.1 和 7.3.3 节)

增加了显式要求,用于检查目标 URI 方案的语义并 拒绝不满足任何相关要求的请求。(第 7.4 节)

媒体类型、媒体范围和 expectation 中的参数可以通过一个或多个 尾随分号为空。(第 5.6.6 节)

“字段值”现在指多个字段行用逗号组合后的值 — 这是目前最常见的用法。要指单个头字段行的值,请使用“字段行 值”。(第 6.3 节)

尾部字段语义现在超越了分块传输编码的具体细节。 尾部字段的使用被进一步限制为:只有当发送方知道字段定义了这种用法时 才允许生成为尾部字段;只有当接收方知道相应字段定义允许并 定义了如何合并时,才允许合并到头部 部分。在所有其他情况下,鼓励实现将 尾部字段单独存储,或者丢弃它们而不是合并。(第 6.5.1 节)

已明确规定源服务器应当优先采用请求 URI 的绝对形式,而不是 Host 头字段 ,以与代理处理保持一致。(第 7.2 节)

RFC 7230 中扩展了 Via 字段 "received-by" 的语法定义,这是由于 URI 中 host 的语法 [URI]发生了 不适合 Via 的更改。为简化起见,我们从 received-by 产生式中删除了 uri-host,因为它可以由现有的 pseudonym 语法涵盖。特别是 ,此更改从 received-by 中主机名称允许的字符集合中移除了逗号 。(第 7.6.3 节)

B.3. 与 RFC 7231 相比的更改

现在建议实现应支持的最小 URI 长度。(第 4.1 节)

以下内容已澄清:字段值中的 CR 和 NUL 应当被拒绝或 映射为 SP,并且在使用字段值之前需要去除其中的前导和尾随空白 。(第 5.5 节)

媒体类型、媒体范围和 expectation 中的参数可以通过一个或多个 尾随分号为空。(第 5.6.6 节)

引入了 HTTP 消息的抽象数据类型,用于跨多个 HTTP 版本抽象定义消息的 组成部分及其语义,而不是依据 [HTTP/1.1] 中 HTTP/1.1 的特定语法形式,并反映 消息解析后的内容。这使得更容易区分 对内容(传达了什么)的要求与对消息传递 语法(如何传达)的要求,并避免把早期协议版本的限制固化 到 HTTP 的未来中。(第 6 节)

术语 "payload" 和 "payload body" 已替换为 "content",以更好地与 其他地方的用法保持一致(例如字段名称中),并避免与 HTTP/2 和 HTTP/3 中的帧 payload 混淆。(第 6.4 节)

术语 "effective request URI" 已替换为 "target URI"。(第 7.1 节)

放宽了对客户端重试的限制,以反映实现行为。(第 9.2.2 节)

澄清了 GET、HEAD 和 DELETE 上的请求主体不可互操作这一事实 。(第 9.3.1、9.3.2 和 9.3.5 节)

允许将 Content-Range 头字段 (第 14.4 节) 用作 PUT 上的请求修饰符。(第 9.3.4 节)

从 OPTIONS 方法的说明中删除了关于设置 Content-Length 的多余要求。(第 9.3.7 节)

删除了在 TRACE 响应中使用 "message/http" 媒体类型的规范性要求 。(第 9.3.8 节)

恢复了 Expect 的基于列表的语法 ,以与 RFC 2616 兼容。(第 10.1.1 节)

Accept 和 Accept-Encoding 允许出现在响应消息中;后者由 [RFC7694]引入。 (第 12.3 节)

已从 Accept 字段定义中删除 "Accept Parameters"(accept-params 和 accept-ext ABNF 产生式) 。(第 12.5.1 节)

Accept-Charset 字段现已弃用。(第 12.5.2 节)

澄清了 Vary 头字段中存在 其他值时 "*" 的语义。(第 12.5.5 节)

范围单位以不区分大小写的方式进行比较。(第 14.1 节)

Accept-Ranges 字段的使用不再限于源服务器。(第 14.3 节)

澄清了创建重定向请求的过程。(第 15.4 节)

增加了状态码 308(先前定义于 [RFC7538]) ,使其定义更靠近状态码 301、302 和 307。(第 15.4.9 节)

增加了状态码 421(先前定义于 [RFC7540] 的第 9.1.2 节),因为 它具有普遍适用性。421 不再定义为 可启发式缓存,因为该响应特定于连接(而不是目标 资源)。(第 15.5.20 节)

增加了状态码 422(先前定义于 [WEBDAV] 的第 11.2 节) ,因为它具有普遍适用性。(第 15.5.21 节)

B.4. 与 RFC 7232 相比的更改

HTTP 的先前修订版本对判断 Last-Modified 是否为强验证器施加了任意的 60 秒限制,以防 Date 和 Last-Modified 值可能由不同的时钟生成,或在准备响应期间于略有 不同的时间生成。本规范已放宽 该限制,以允许合理判断。(第 8.8.2.2 节)

删除了 If-Match 和 If-Unmodified-Since 的一种边缘情况要求, 该要求规定,如果验证失败是因为更改请求已经应用,则 不得在 2xx 响应中发送验证器。(第 13.1.1 和 13.1.4 节)

澄清了 If-Unmodified-Since 不适用于没有 修改时间概念的资源。(第 13.1.4 节)

现在可以在处理请求内容之前对前置条件求值,而无需 等到响应本来会成功时。(第 13.2 节)

B.5. 与 RFC 7233 相比的更改

重构了 range-unit 和 ranges-specifier 语法,以简化并减少 bytes 与其他(扩展)范围单位之间人为的差异,通过将范围单位通用地定义为 token,并将 扩展放在 range-spec(other-range)的范围内,移除了 other-range-unit 的重叠 语法。这消除了列表语法(逗号)在所有范围集合中的作用歧义,包括扩展范围单位中 用于表示包含多个范围的 range-set。将扩展语法移入 range 说明符还允许单独规定特定于字节范围的协议。

现在可以为扩展方法定义 Range 处理。(第 14.2 节)

描述了使用 Content-Range 头 字段 (第 14.4 节) 作为请求修饰符来执行部分 PUT。(第 14.5 节)

B.6. 与 RFC 7235 相比的更改

无。

B.7. 与 RFC 7538 相比的更改

无。

B.8. 与 RFC 7615 相比的更改

无。

B.9. 与 RFC 7694 相比的更改

本规范包含 [RFC7694] 中定义的扩展,但省略示例和部署注意事项。

致谢

除当前编辑外,以下人员因 对 HTTP 早期发展及其核心规范所作的贡献而值得特别致谢:Marc Andreessen, Tim Berners-Lee, Robert Cailliau, Daniel W. Connolly, Bob Denny, John Franks, Jim Gettys, Jean-François Groff, Phillip M. Hallam-Baker, Koen Holtman, Jeffery L. Hostetler, Shel Kaphan, Dave Kristol, Yves Lafon, Scott D. Lawrence, Paul J. Leach, Håkon W. Lie, Ari Luotonen, Larry Masinter, Rob McCool, Jeffrey C. Mogul, Lou Montulli, David Morris, Henrik Frystyk Nielsen, Dave Raggett, Eric Rescorla, Tony Sanders, Lawrence C. Stewart, Marc VanHeyningen, 和 Steve Zilles。

本文档建立在过去 HTTP 规范中的众多贡献之上, 包括 [HTTP/1.0], [RFC2068], [RFC2145], [RFC2616], [RFC2617], [RFC2818], [RFC7230], [RFC7231], [RFC7232], [RFC7233], [RFC7234], 和 [RFC7235]。 这些文档中的致谢仍然适用。

自 2014 年以来,以下贡献者通过报告 错误、提出深刻问题、起草或审阅文本以及评估议题,帮助改进了本规范:

Alan Egerton, Alex Rousskov, Amichai Rothman, Amos Jeffries, Anders Kaseorg, Andreas Gebhardt, Anne van Kesteren, Armin Abfalterer, Aron Duby, Asanka Herath, Asbjørn Ulsberg, Asta Olofsson, Attila Gulyas, Austin Wright, Barry Pollard, Ben Burkert, Benjamin Kaduk, Björn Höhrmann, Brad Fitzpatrick, Chris Pacejo, Colin Bendell, Cory Benfield, Cory Nelson, Daisuke Miyakawa, Dale Worley, Daniel Stenberg, Danil Suits, David Benjamin, David Matson, David Schinazi, Дилян Палаузов (Dilyan Palauzov), Eric Anderson, Eric Rescorla, Éric Vyncke, Erik Kline, Erwin Pe, Etan Kissling, Evert Pot, Evgeny Vrublevsky, Florian Best, Francesca Palombini, Igor Lubashev, James Callahan, James Peach, Jeffrey Yasskin, Kalin Gyokov, Kannan Goundan, 奥 一穂 (Kazuho Oku), Ken Murchison, Krzysztof Maczyński, Lars Eggert, Lucas Pardue, Martin Duke, Martin Dürst, Martin Thomson, Martynas Jusevičius, Matt Menke, Matthias Pigulla, Mattias Grenfeldt, Michael Osipov, Mike Bishop, Mike Pennisi, Mike Taylor, Mike West, Mohit Sethi, Murray Kucherawy, Nathaniel J. Smith, Nicholas Hurley, Nikita Prokhorov, Patrick McManus, Piotr Sikora, Poul-Henning Kamp, Rick van Rein, Robert Wilton, Roberto Polli, Roman Danyliw, Samuel Williams, Semyon Kholodnov, Simon Pieters, Simon Schüppel, Stefan Eissing, Taylor Hunt, Todd Greer, Tommy Pauly, Vasiliy Faronov, Vladimir Lashchev, Wenbo Zhu, William A. Rowe Jr., Willy Tarreau, Xingwei Liu, Yishuai Li, 和 Zaheduzzaman Sarker。

索引

1 2 3 4 5 A B C D E F G H I K L M N O P R S T U V W X

作者地址

Roy T. Fielding (编辑)
Adobe
345 Park Ave
San Jose, CA 95110
美利坚 合众国
电子邮件: fielding@gbiv.com
URI: https://roy.gbiv.com/
Mark Nottingham (编辑)
Fastly
Prahran
澳大利亚
电子邮件: mnot@mnot.net
URI: https://www.mnot.net/
Julian Reschke (编辑)
greenbytes GmbH
Hafenweg 16
48155 Münster
德国
电子邮件: julian.reschke@greenbytes.de
URI: https://greenbytes.de/tech/webdav/