互联网工程任务组(IETF) L. Dusseault
请求评论 (Request for Comments): 5789 Linden Lab
类别: 标准路线 (Standards Track) J. Snell
ISSN: 2070-1721 2010 年 3 月

HTTP 的 PATCH 方法


摘要

若干扩展超文本传输协议(HTTP)的应用需要对资源进行部分修改的功能。现有的 HTTP PUT 方法仅允许对文档进行完整替换。本提案增加了一种新的 HTTP 方法 PATCH,用于修改已有的 HTTP 资源。

本备忘录的状态

这是一个互联网标准路线(Standards Track)文档。

本文件是互联网工程任务组(IETF)的产物,代表 IETF 社区的共识。它已接受公开审查并获得互联网工程指导组(IESG)批准发表。有关互联网标准的更多信息,请参见 RFC 5741 的第 2 节

有关本文件当前状态、任何勘误以及如何提供反馈的信息,可在 http://www.rfc-editor.org/info/rfc5789 获得。

Copyright Notice

Copyright (c) 2010 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 (http://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 Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.

1. 介绍

This specification defines the new HTTP/1.1 [RFC2616] method, PATCH, which is used to apply partial modifications to a resource.

需要一种新方法以改善互操作性并防止错误。PUT 方法已被定义为使用完整的新主体覆盖资源,不能重用于执行部分更改。否则,代理和缓存,甚至客户端和服务器,可能会对操作结果产生混淆。POST 已被用于类似目的但没有广泛的互操作性(例如,没有标准方法来发现补丁格式支持)。PATCH 在早期的 HTTP 规范中有提及,但未被完整定义。

在本文档中,关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY" 和 "OPTIONAL" 的解释参见 [RFC2119]

此外,本文档使用在 [RFC2616] 第 2.1 节中定义的 ABNF 语法。

2. PATCH 方法

PATCH 方法请求将请求实体中描述的一组更改应用到由 Request-URI 标识的资源。这组更改以一种称为“补丁文档”的格式表示,并由一个媒体类型来标识。如果 Request-URI 未指向现有资源,服务器可以根据补丁文档类型(即它是否可以逻辑上修改空资源)、权限等条件选择创建新资源。

PUT 与 PATCH 请求之间的差异体现在服务器处理封装实体以修改由 Request-URI 标识的资源的方式上。在 PUT 请求中,封装实体被视为存储在源服务器上的资源的修改后版本,客户端请求将存储的版本替换。然 而对于 PATCH,封装实体包含一组指令,描述应如何修改当前驻留在源服务器上的资源以生成新版本。PATCH 方法影响由 Request-URI 标识的资源,并且它也可能对其他资源产生副作用;即应用 PATCH 可能会创建新资源或修改现有资源。

根据 [RFC2616] 第 9.1 节的定义,PATCH 既不是安全的,也不是幂等的。

PATCH 请求可以以某种方式发出使其成为幂等的,这也有助于防止在相近时间对同一资源的两个 PATCH 请求发生冲突而导致的不良后果。来自多个 PATCH 请求的冲突可能比 PUT 冲突更危险,因为某些补丁格式需要从已知的基点运行,否则会破坏资源。使用此类补丁应用的客户端应使用条件请求,使得如果资源自客户端上次访问后已被更新,请求将失败。例如,客户端可以在 PATCH 请求上使用 If-Match 报头中的强 ETag [RFC2616]

也存在某些补丁格式不需要从已知基点运行的情况(例如,将文本行追加到日志文件,或向数据库表追加不会冲突的行),在这些情况下客户端请求不需要采取相同的谨慎措施。

服务器 MUST 原子性地应用整组更改,并且在操作期间绝不提供(例如,对 GET 的响应中)部分修改的表示。如果整个补丁文档无法成功应用,则服务器 MUST NOT 应用任何更改。什么构成成功的 PATCH 的判断可能因补丁文档和被修改的资源类型而异。例如,常见的 diff 工具可以生成适用于目录层次中多个文件的补丁文档。原子性要求对所有直接受影响的文件都适用。有关状态码和可能的错误条件的详细信息,请参阅 “错误处理”,第 2.2 节

如果请求通过缓存转发,且 Request-URI 标识了一个或多个当前被缓存的实体,则这些条目应该被视为陈旧。只有当响应包含显式的新鲜度信息(例如 Expires 报头或 "Cache-Control: max-age" 指令)并且包含与 Request-URI 匹配的 Content-Location 报头以指示 PATCH 响应体是一个资源表示时,PATCH 的响应才是可缓存的。被缓存的 PATCH 响应只能用于响应随后的 GET 和 HEAD 请求;它 MUST NOT 用于响应其他方法(特别是 PATCH)。

注意,请求中包含的实体首部只适用于所包含的补丁文档,并且 MUST NOT 应用于被修改的资源。因此,请求中可能存在 Content-Language 报头,但它仅表示补丁文档具有某种语言(无更多含义)。服务器不应存储此类首部,除非作为跟踪信息,也不应以与 PUT 请求相同的方式使用这些首部值。因此,本文档未指定通过首部修改文档的 Content-Type 或 Content-Language 值的方法,尽管可以通过补丁文档设计出一种机制来实现该目标。

不能保证资源可以用 PATCH 修改。此外,预期不同的补丁文档格式适用于不同类型的资源,并且没有单一格式适用于所有类型的资源。因此,未要求实现支持单一默认的补丁文档格式。服务器 MUST 确保接收的补丁文档适用于由 Request-URI 标识的资源类型。

客户端需要在何时使用 PATCH 而不是 PUT 之间做出选择。例如,如果补丁文档的大小大于用于 PUT 的新资源数据的大小,则可能更适合使用 PUT 而不是 PATCH。与 POST 的比较更为复杂,因为 POST 的使用方式多种多样,如果服务器选择,POST 可以包含类似 PUT 或 PATCH 的操作。如果操作不会以可预测的方式修改由 Request-URI 标识的资源,则应考虑使用 POST 而不是 PATCH 或 PUT。

2.1. 一个简单的 PATCH 示例

PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 100

[description of changes]

该示例演示了在现有资源上使用假设的补丁文档。

对现有文本文件的成功 PATCH 响应:

HTTP/1.1 204 No Content
Content-Location: /file.txt
ETag: "e0023aa4f"

使用 204 响应码是因为响应不携带消息体(而 200 响应通常会有消息体)。注意也可以使用其他成功状态码。

此外,ETag 响应报头字段包含通过应用 PATCH 在 http://www.example.com/file.txt 上创建的实体的 ETag,如 Content-Location 响应报头字段所示。

2.2. 错误处理

有若干已知情况会导致 PATCH 请求失败。

格式错误的补丁文档:
当服务器确定客户端提供的补丁文档格式不正确时,应返回 400 (Bad Request) 响应。格式错误的定义取决于所选的补丁文档格式。
不支持的补丁文档:
当客户端发送服务器不支持用于由 Request-URI 标识的资源的补丁文档格式时,可使用 415 (Unsupported Media Type) 响应来指定此情况。此类响应应包含如 第 3.1 节 所述的 Accept-Patch 响应报头,以通知客户端服务器支持哪些补丁文档媒体类型。
无法处理的请求:
当服务器理解补丁文档且补丁文档的语法看起来有效,但服务器无法处理该请求时,可使用 422 (Unprocessable Entity) 响应(参见 [RFC4918] 第 11.2 节)。这可能包括尝试以会导致资源变为无效的方式修改资源;例如,对一个本应为 well-formed 的 XML 文档的修改导致其不再是 well-formed。还可能出现更具体的错误(例如“状态冲突”),这些错误也可以用该状态码指示,但更具体的错误通常对客户端更有帮助。
资源未找到:
当客户端试图将补丁文档应用到不存在的资源,但所选的补丁文档无法应用于不存在的资源时,可使用 404 (Not Found) 状态码。
状态冲突:
当由于资源的当前状态而无法应用请求时,可使用 409 (Conflict) 状态码。例如,如果客户端试图应用结构性修改但假定存在的结构不存在(在 XML 的情况下,补丁可能指定将元素 'foo' 更改为元素 'bar',但元素 'foo' 可能并不存在)。
修改冲突:
当客户端使用 If-Match 或 If-Unmodified-Since 报头定义前置条件并且该前置条件失败时,返回 412 (Precondition Failed) 错误对客户端最有用。然而,如果请求中没有前置条件,则该响应没有意义。在服务器检测到可能的修改冲突且请求中未定义前置条件的情况下,服务器可以返回 409 (Conflict) 响应。
并发修改:
某些 PATCH 的应用可能要求服务器按接收顺序处理请求。如果服务器在这些限制下运行,并且收到并发请求以修改同一资源,但无法对这些请求排队处理,服务器可以通过使用 409 (Conflict) 响应来指示该错误。

注意 409 Conflict 响应为客户端提供了相对一致的信息。根据应用和补丁格式的性质,客户端可能能够按原样重新发出请求(例如,向日志文件追加一行的指令),也可能需要检索资源内容以重新计算补丁,或者必须放弃操作。

在适当情况下,也可以使用其他 HTTP 状态码。

错误响应的实体主体应包含足够的信息以向客户端传达错误的性质。响应实体的 content-type 在实现之间可以不同。

3. 在 OPTIONS 中宣告支持

服务器可以通过在 HTTP/1.1 定义的 "Allow" OPTIONS 响应报头的允许方法列表中添加 PATCH 来宣告其对 PATCH 方法的支持。即使 Accept-Patch 报头缺失,PATCH 方法也可以出现在 "Allow" 报头中,在这种情况下不会宣告可用的补丁文档列表。

3.1. Accept-Patch 报头

本规范引入了一个新的响应报头 Accept-Patch,用于指定服务器接受的补丁文档格式。Accept-Patch 应出现在对任何支持 PATCH 方法的资源的 OPTIONS 响应中。对任意方法的响应中出现 Accept-Patch 报头是一个隐含指示,表示对由 Request-URI 标识的资源允许使用 PATCH。在该报头中出现特定补丁文档格式表示该特定格式被允许用于由 Request-URI 标识的资源。

Accept-Patch = "Accept-Patch" ":" 1#media-type 

Accept-Patch 报头指定了按 [RFC2616] 第 3.7 节定义的以逗号分隔的媒体类型列表(可带可选参数)。

示例:

Accept-Patch: text/example;charset=utf-8

3.2. 示例 OPTIONS 请求与响应

[request]

OPTIONS /example/buddies.xml HTTP/1.1
Host: www.example.com

[response]

HTTP/1.1 200 OK
Allow: GET, PUT, POST, OPTIONS, HEAD, DELETE, PATCH
Accept-Patch: application/example, text/example

这些示例显示了一个通常支持 PATCH 的服务器,使用两个假设的补丁文档格式。

4. IANA 考量

4.1. Accept-Patch 响应报头

Accept-Patch 响应报头已被添加到永久注册表(参见 [RFC3864])。

Header field name:
Accept-Patch
Applicable Protocol:
HTTP
Author/Change controller:
IETF
Specification document:
this specification

5. 安全性考量

PATCH 的安全性考量几乎与 PUT 的安全性考量相同(参见 [RFC2616] 第 9.6 节)。这些包括对请求进行授权(可能通过访问控制和/或认证)以及确保数据不会因传输错误或意外覆盖而损坏。用于 PUT 的任何机制也可用于 PATCH。下列注意事项尤其适用于 PATCH。

被补丁化的文档比整体替换的文档更容易被破坏,但可以通过使用诸如 ETag 和 If-Match 请求报头等条件请求机制来应对这一问题(如第 2 节 所述)。如果 PATCH 请求失败,客户端可以发出 GET 请求以查看资源的状态。在某些情况下,客户端可能能够检查资源的内容以确定是否可以重新发送 PATCH 请求,但在其他情况下,尝试将失败并且/或需要用户验证意图。如果底层传输通道在接收到 PATCH 响应之前失败或发生超时,客户端可能必须发出 GET 请求以查看请求是否已被应用。客户端可能希望确保 GET 请求绕过缓存,使用 HTTP 规范中描述的机制(例如,参见 [RFC2616] 第 13.1.6 节)。

有时 HTTP 中间件可能会通过检查 PUT/POST 请求的主体或 GET 响应来检测通过 HTTP 发送的病毒。PATCH 方法使这种监测更为复杂,因为源文档或补丁文档本身可能都不是病毒,但结果可能是。这一安全性考量与字节范围下载、下载补丁文档、上传压缩文件等带来的问题并无实质差别。

单个补丁文档将具有其自身特定的安全性考量,这些考量可能取决于被补丁的资源类型而变化。例如,被补丁的二进制资源的考量将不同于被补丁的 XML 文档。服务器必须采取足够的预防措施,确保恶意客户端不能通过使用 PATCH 耗尽服务器资源(例如 CPU、磁盘 I/O)。

6. 参考文献

6.1. 规范性参考文献

[RFC2119]
Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, March 1997.
[RFC2616]
Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, “Hypertext Transfer Protocol -- HTTP/1.1”, RFC 2616, June 1999.
[RFC3864]
Klyne, G., Nottingham, M., and J. Mogul, “Registration Procedures for Message Header Fields”, BCP 90, RFC 3864, September 2004.

6.2. 信息性参考文献

[RFC4918]
Dusseault, L., “HTTP Extensions for Web Distributed Authoring and Versioning (WebDAV)”, RFC 4918, June 2007.

Appendix A. 致谢

PATCH 并非新概念,它首次出现在 Roy Fielding 和 Henrik Frystyk 撰写的 HTTP 1.1 草案中,也出现在 RFC 2068 的第 19.6.1.1 节中。

感谢 Adam Roach、Chris Sharp、Julian Reschke、Geoff Clemm、Scott Lawrence、Jeffrey Mogul、Roy Fielding、Greg Stein、Jim Luther、Alex Rousskov、Jamie Lokier、Joe Hildebrand、Mark Nottingham、Michael Balloni、Cyrus Daboo、Brian Carpenter、John Klensin、Eliot Lear、SM,以及 Bernie Hoeneisen 对本文档的审阅和建议。特别是,Julian Reschke 多次审阅,提出了许多有用建议,并对本文档的发表起到了关键作用。

作者地址

Lisa Dusseault
Linden Lab
945 Battery Street
San Francisco, CA 94111
USA
Email: lisa.dusseault@gmail.com
James M. Snell
Email: jasnell@gmail.com
URI: http://www.snellspace.com