Skip to main content

4. Request Methods (请求方法)

4.1. Overview (概述)

请求方法令牌 (request method token) 是请求语义的主要来源, 它指示客户端发出此请求的目的以及客户端期望的成功结果。

请求方法的语义可能会被请求中出现的某些头字段的语义进一步特化 (Section 5), 前提是这些额外的语义不与方法冲突。例如, 客户端可以发送条件请求头字段 (Section 5.2) 使请求的操作取决于目标资源的当前状态 ([RFC7232])。

method = token

HTTP 最初被设计为可用作分布式对象系统的接口。请求方法被设想为对目标资源应用语义, 就像在已识别的对象上调用已定义的方法会应用语义一样。方法令牌是区分大小写的, 因为它可能被用作基于对象的系统的网关, 而这些系统具有区分大小写的方法名。

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

本规范定义了一些在 HTTP 中常用的标准化方法, 如下表所示。按照惯例, 标准化方法以全大写的 US-ASCII 字母定义。

MethodSafe (安全)Idempotent (幂等)Description (描述)
GETYesYes传输目标资源的当前表示。
HEADYesYes与 GET 相同, 但仅传输状态行和头部分。
POSTNoNo对请求载荷执行资源特定的处理。
PUTNoYes用请求载荷替换目标资源的所有当前表示。
DELETENoYes删除目标资源的所有当前表示。
CONNECTNoNo建立到由目标资源标识的服务器的隧道。
OPTIONSYesYes描述目标资源的通信选项。
TRACEYesYes沿着到目标资源的路径执行消息环回测试。

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

本规范范围之外的其他方法已被标准化以在 HTTP 中使用。所有此类方法都应该在由 IANA 维护的 "Hypertext Transfer Protocol (HTTP) Method Registry" 中注册, 如 Section 8.1 所定义。

目标资源允许的方法集可以在 Allow 头字段 (Section 7.4.1) 中列出。但是, 允许的方法集可能会动态更改。当源服务器接收到无法识别或未实现的请求方法时, 源服务器应该 (SHOULD) 以 501 (Not Implemented) 状态码响应。当接收到源服务器已知但不允许用于目标资源的请求方法时, 源服务器应该 (SHOULD) 以 405 (Method Not Allowed) 状态码响应。

4.2. Common Method Properties (通用方法属性)

4.2.1. Safe Methods (安全方法)

如果请求方法的已定义语义本质上是只读的, 即客户端不请求也不期望因对目标资源应用安全方法而导致源服务器上的任何状态更改, 则该请求方法被认为是"安全的" (safe)。同样, 合理使用安全方法不应导致任何伤害、财产损失或对源服务器造成异常负担。

这种对安全方法的定义并不排除实现包含可能有害的、并非完全只读的或在调用安全方法时产生副作用的行为。然而, 重要的是, 客户端没有请求这些额外的行为, 并且不能为此承担责任。例如, 大多数服务器在每次响应完成时都会将请求信息附加到访问日志文件中, 无论使用什么方法, 这被认为是安全的, 即使日志存储可能变满并导致服务器崩溃。同样, 通过在 Web 上选择广告而发起的安全请求通常会产生向广告账户收费的副作用。

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

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

用户代理应该 (SHOULD) 在向用户呈现潜在操作时区分安全和不安全的方法, 以便在请求不安全操作之前让用户意识到它。

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

4.2.2. Idempotent Methods (幂等方法)

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

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

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

4.2.3. Cacheable Methods (可缓存方法)

请求方法可以被定义为"可缓存的" (cacheable), 以指示允许存储对它们的响应以供将来重用, 具体要求请参见 [RFC7234]。一般来说, 不依赖于当前或权威响应的安全方法被定义为可缓存的, 本规范将 GET、HEAD 和 POST 定义为可缓存的, 尽管绝大多数缓存实现仅支持 GET 和 HEAD。

4.3. Method Definitions (方法定义)

4.3.1. GET

GET 方法请求传输目标资源的当前选定表示。GET 是信息检索的主要机制, 也是几乎所有性能优化的焦点。因此, 当人们谈论通过 HTTP 检索某些可识别的信息时, 他们通常指的是发出 GET 请求。

很容易将资源标识符视为远程文件系统路径名, 并将表示视为此类文件内容的副本。这是错误的。响应 GET 而返回的表示不一定只是源服务器存储的资源内容。相反, 它们是被选定的 (通过内容协商) 并动态生成的, 取决于请求。

GET 请求消息中的载荷没有定义的语义, 在 GET 请求上发送载荷主体可能会导致某些现有实现拒绝该请求。

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

4.3.2. HEAD

HEAD 方法与 GET 相同, 只是服务器绝对不能 (MUST NOT) 在响应中发送消息主体 (即响应在头部分结束时终止)。服务器应该 (SHOULD) 在响应 HEAD 请求时发送与 GET 请求相同的头字段, 除了载荷头字段 (Section 3.3) 可以 (MAY) 被省略。此方法可用于获取关于所选表示的元数据, 而无需传输表示数据, 并且通常用于测试超文本链接的有效性、可访问性和最近的修改。

HEAD 请求消息中的载荷没有定义的语义, 在 HEAD 请求上发送载荷主体可能会导致某些现有实现拒绝该请求。

对 HEAD 请求的响应是可缓存的, 缓存可以 (MAY) 使用它来满足后续的 HEAD 请求, 除非 Cache-Control 头字段另有指示 ([RFC7234] 的 Section 5.2)。HEAD 响应也可能对先前缓存的 GET 响应产生影响, 参见 [RFC7234] 的 Section 4.3.5。

4.3.3. POST

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

  • 向数据处理进程提供数据块, 例如输入到 HTML 表单中的字段;

  • 向公告板、新闻组、邮件列表、博客或类似的文章组发布消息;

  • 创建源服务器尚未识别的新资源; 以及,

  • 将数据附加到资源的现有表示。

源服务器通过根据处理 POST 请求的结果选择适当的状态码来指示响应语义, 本规范定义的几乎所有状态码都可能在对 POST 的响应中接收到 (例外是 206 (Partial Content)、304 (Not Modified) 和 416 (Range Not Satisfiable))。

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

只有当 POST 请求的响应包含明确的新鲜度信息时, 它们才是可缓存的 (参见 [RFC7234] 的 Section 4.2.1)。但是, POST 缓存并未广泛实现。对于源服务器希望客户端能够缓存 POST 结果并可以被后续 GET 重用的情况, 源服务器可以 (MAY) 发送包含结果的 200 (OK) 响应和一个与 POST 的有效请求 URI 具有相同值的 Content-Location 头字段 (Section 3.1.4.2)。

如果处理 POST 的结果等效于现有资源的表示, 源服务器可以 (MAY) 通过发送 303 (See Other) 响应并在 Location 字段中包含现有资源的标识符来将用户代理重定向到该资源。这具有向用户代理提供资源标识符并通过更适合共享缓存的方法传输表示的好处, 尽管如果用户代理尚未缓存表示, 则会产生额外请求的成本。

4.3.4. PUT

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

如果目标资源没有当前表示并且 PUT 成功创建了一个, 那么源服务器必须 (MUST) 通过发送 201 (Created) 响应通知用户代理。如果目标资源确实有当前表示并且该表示根据所包含表示的状态成功修改, 那么源服务器必须 (MUST) 发送 200 (OK) 或 204 (No Content) 响应以指示请求成功完成。

源服务器应该 (SHOULD) 验证 PUT 表示与服务器对目标资源的任何约束一致, 这些约束不能被 PUT 更改或未被 PUT 更改。当源服务器使用与 URI 相关的内部配置信息来设置 GET 响应上的表示元数据值时, 这尤其重要。当 PUT 表示与目标资源不一致时, 源服务器应该 (SHOULD) 通过转换表示或更改资源配置使它们一致, 或者以包含足够信息来解释为什么表示不合适的适当错误消息进行响应。建议使用 409 (Conflict) 或 415 (Unsupported Media Type) 状态码, 后者特定于 Content-Type 值的约束。

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

a. 重新配置目标资源以反映新的媒体类型;

b. 在将其保存为新资源状态之前, 将 PUT 表示转换为与资源一致的格式; 或,

c. 以 415 (Unsupported Media Type) 响应拒绝请求, 指示目标资源限于 "text/html", 可能包括指向不同资源的链接, 该资源将是新表示的合适目标。

HTTP 没有确切定义 PUT 方法如何影响源服务器的状态, 超出用户代理请求的意图和源服务器响应的语义所能表达的范围。它没有定义资源在该词的任何意义上可能是什么, 除了通过 HTTP 提供的接口。它没有定义资源状态如何被"存储", 也没有定义这样的存储如何因资源状态的更改而更改, 也没有定义源服务器如何将资源状态转换为表示。一般来说, 资源接口背后的所有实现细节都是由服务器有意隐藏的。

源服务器绝对不能 (MUST NOT) 在对 PUT 的成功响应中发送验证器头字段 (Section 7.2), 例如 ETagLast-Modified 字段, 除非请求的表示数据是在未对主体应用任何转换的情况下保存的 (即资源的新表示数据与 PUT 请求中接收的表示数据相同) 并且验证器字段值反映了新表示。此要求允许用户代理知道其内存中的表示主体因 PUT 而保持当前状态, 因此不需要从源服务器再次检索, 并且响应中接收的新验证器可用于未来的条件请求, 以防止意外覆写 (Section 5.2)。

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

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

应用于目标资源的 PUT 请求可能对其他资源产生副作用。例如, 一篇文章可能有一个用于标识"当前版本"的 URI (一个资源), 该 URI 与标识每个特定版本的 URI (在某个时刻与当前版本资源共享相同状态的不同资源) 是分开的。对"当前版本" URI 的成功 PUT 请求因此可能会创建新的版本资源以及更改目标资源的状态, 并且还可能导致在相关资源之间添加链接。

在给定目标资源上允许 PUT 的源服务器必须 (MUST) 对包含 Content-Range 头字段 ([RFC7233] 的 Section 4.2) 的 PUT 请求发送 400 (Bad Request) 响应, 因为载荷可能是被错误地作为完整表示 PUT 的部分内容。部分内容更新可以通过针对单独标识的资源 (其状态与较大资源的一部分重叠) 或通过使用专门为部分更新定义的不同方法 (例如, [RFC5789] 中定义的 PATCH 方法) 来实现。

对 PUT 方法的响应是不可缓存的。如果成功的 PUT 请求通过缓存, 该缓存对有效请求 URI 有一个或多个存储的响应, 则这些存储的响应将被无效 (参见 [RFC7234] 的 Section 4.4)。

4.3.5. DELETE

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

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

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

如果成功应用了 DELETE 方法, 源服务器应该 (SHOULD) 发送 202 (Accepted) 状态码 (如果操作可能成功但尚未执行)、204 (No Content) 状态码 (如果操作已执行且无需提供进一步信息) 或 200 (OK) 状态码 (如果操作已执行且响应消息包含描述状态的表示)。

DELETE 请求消息中的载荷没有定义的语义, 在 DELETE 请求上发送载荷主体可能会导致某些现有实现拒绝该请求。

对 DELETE 方法的响应是不可缓存的。如果 DELETE 请求通过缓存, 该缓存对有效请求 URI 有一个或多个存储的响应, 则这些存储的响应将被无效 (参见 [RFC7234] 的 Section 4.4)。

4.3.6. CONNECT

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

CONNECT 仅用于对代理的请求。接收到针对自身的 CONNECT 请求的源服务器可以 (MAY) 以 2xx (Successful) 状态码响应以指示已建立连接。但是, 大多数源服务器不实现 CONNECT。

发送 CONNECT 请求的客户端必须 (MUST) 发送权限形式的请求目标 ([RFC7230] 的 Section 5.3), 即请求目标仅由隧道目标的主机名和端口号组成, 用冒号分隔。例如,

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

接收方代理可以通过直接连接到请求目标或 (如果配置为使用另一个代理) 通过将 CONNECT 请求转发到下一个入站代理来建立隧道。任何 2xx (Successful) 响应都表示发送者 (和所有入站代理) 将在结束成功响应头部分的空行之后立即切换到隧道模式, 该空行之后接收的数据来自由请求目标标识的服务器。任何非成功响应都表示隧道尚未形成, 并且连接仍受 HTTP 管理。

当隧道中介检测到任一方已关闭其连接时, 隧道即关闭: 中介必须 (MUST) 尝试将来自已关闭方的任何未完成数据发送到另一方, 关闭两个连接, 然后丢弃任何剩余的未交付数据。

代理认证可用于建立创建隧道的权限。例如,

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

建立到任意服务器的隧道存在重大风险, 特别是当目标是不适用于 Web 流量的知名或保留 TCP 端口时。例如, CONNECT 到 "example.com:25" 将建议代理连接到 SMTP 流量的保留端口, 如果允许, 可能会诱使代理转发垃圾邮件。支持 CONNECT 的代理应该 (SHOULD) 将其使用限制为有限的已知端口集或可配置的安全请求目标列表。

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

CONNECT 请求消息中的载荷没有定义的语义, 在 CONNECT 请求上发送载荷主体可能会导致某些现有实现拒绝该请求。

对 CONNECT 方法的响应是不可缓存的。

4.3.7. OPTIONS

OPTIONS 方法请求有关目标资源可用的通信选项的信息, 无论是在源服务器还是在中间中介处。此方法允许客户端确定与资源相关的选项和/或要求, 或服务器的功能, 而不暗示资源操作。

以星号 ("") 作为请求目标的 OPTIONS 请求 ([RFC7230] 的 Section 5.3) 一般应用于服务器, 而不是特定资源。由于服务器的通信选项通常取决于资源, 因此 "" 请求仅作为"ping"或"no-op"类型的方法有用, 它除了允许客户端测试服务器的功能外什么都不做。例如, 这可用于测试代理的 HTTP/1.1 一致性 (或缺乏一致性)。

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

生成对 OPTIONS 的成功响应的服务器应该 (SHOULD) 发送任何可能指示服务器实现的可选功能并适用于目标资源的头字段 (例如 Allow), 包括本规范未定义的潜在扩展。响应载荷 (如果有) 也可能以机器或人类可读的表示形式描述通信选项。本规范没有定义此类表示的标准格式, 但可能由 HTTP 的未来扩展定义。如果响应中不发送载荷主体, 服务器必须 (MUST) 生成值为"0"的 Content-Length 字段。

客户端可以 (MAY) 在 OPTIONS 请求中发送 Max-Forwards 头字段以针对请求链中的特定接收者 (参见 Section 5.1.2)。代理绝对不能 (MUST NOT) 在转发请求时生成 Max-Forwards 头字段, 除非该请求是在具有 Max-Forwards 字段的情况下接收的。

生成包含载荷主体的 OPTIONS 请求的客户端必须 (MUST) 发送描述表示媒体类型的有效 Content-Type 头字段。虽然本规范没有定义此类载荷的任何用途, 但 HTTP 的未来扩展可能会使用 OPTIONS 主体对目标资源进行更详细的查询。

对 OPTIONS 方法的响应是不可缓存的。

4.3.8. TRACE

TRACE 方法请求对请求消息进行远程应用级环回。请求的最终接收者应该 (SHOULD) 将接收到的消息 (不包括下面描述的某些字段) 作为 200 (OK) 响应的消息主体反射回客户端, 响应的 Content-Type 为 "message/http" ([RFC7230] 的 Section 8.3.1)。最终接收者是源服务器或第一个在请求中接收到 Max-Forwards 值为零 (0) 的服务器 (Section 5.1.2)。

客户端绝对不能 (MUST NOT) 在 TRACE 请求中生成包含可能被响应披露的敏感数据的头字段。例如, 用户代理在 TRACE 请求中发送存储的用户凭据 [RFC7235] 或 cookie [RFC6265] 将是愚蠢的。请求的最终接收者在生成响应主体时应该 (SHOULD) 排除任何可能包含敏感数据的请求头字段。

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

客户端绝对不能 (MUST NOT) 在 TRACE 请求中发送消息主体。

对 TRACE 方法的响应是不可缓存的。