如何在 REST 中支持部分更新 (PATCH)

发布于 2024-12-15 13:40:21 字数 1513 浏览 1 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

忆离笙 2024-12-22 13:40:21

根据 RFC5789 (https://www.rfc-editor.org/rfc/rfc5789),这正是 PATCH 的用途:

几个扩展超文本传输​​协议(HTTP)的应用程序
需要一个功能来进行部分资源修改。现有的
HTTP PUT 方法只允许完全替换一个文档。
该提案添加了一个新的 HTTP 方法 PATCH,以修改现有的
HTTP 资源。

PATCH和PUT的区别描述为:

PUT 和 PATCH 请求之间的差异体现在
服务器处理所附实体以修改资源的方式
由请求 URI 标识。在 PUT 请求中,包含的实体
被认为是存储在资源上的修改版本
原始服务器,客户端请求存储的版本
被替换。然而,使用 PATCH,封闭的实体包含一组
描述资源当前如何驻留在
应修改源服务器以生成新版本。

还描述了 POST 的局限性:

已定义 PUT 方法来覆盖资源
具有全新的主体,并且不能重复使用来进行部分更改。
否则,代理和缓存,甚至客户端和服务器都可能会受到影响
对操作的结果感到困惑。 POST 已被使用,但是
没有广泛的互操作性(一方面,没有标准的方法来
发现补丁格式支持)[...]

我建议您阅读 RFC 并做出自己的决定,但对我来说,这似乎相当明确 - PATCH 请求应作为部分更新进行处理。 (注意,它们不是幂等的,与 PUT 不同。)

编辑:正如 Eugene 在评论中指出的那样,尽管 PATCH 请求是 “既不安全也不幂等,如 [RFC2616] 定义的那样”,但它们可以所以:

PATCH 请求可以以幂等的方式发出,
这也有助于防止两个人之间的碰撞产生不良后果
在相似的时间范围内对同一资源发出 PATCH 请求。
来自多个 PATCH 请求的冲突可能比
PUT 冲突,因为某些补丁格式需要从
已知基点,否则它们会破坏资源。客户
使用这种补丁应用程序应该使用条件请求
如果资源已更新,请求将失败
自客户端上次访问资源以来。例如,客户
可以在 PATCH 上的 If-Match 标头中使用强 ETag [RFC2616]
请求。

According to RFC5789 (https://www.rfc-editor.org/rfc/rfc5789), this is precisely what PATCH is for:

Several applications extending the Hypertext Transfer Protocol (HTTP)
require a feature to do partial resource modification. The existing
HTTP PUT method only allows a complete replacement of a document.
This proposal adds a new HTTP method, PATCH, to modify an existing
HTTP resource.

The distinction between PATCH and PUT is described as:

The difference between the PUT and PATCH requests is reflected in the
way the server processes the enclosed entity to modify the resource
identified by the Request-URI. In a PUT request, the enclosed entity
is considered to be a modified version of the resource stored on the
origin server, and the client is requesting that the stored version
be replaced. With PATCH, however, the enclosed entity contains a set
of instructions describing how a resource currently residing on the
origin server should be modified to produce a new version.

The limitations of POST are also described:

The PUT method is already defined to overwrite a resource
with a complete new body, and cannot be reused to do partial changes.
Otherwise, proxies and caches, and even clients and servers, may get
confused as to the result of the operation. POST is already used but
without broad interoperability (for one, there is no standard way to
discover patch format support) [...]

I would suggest you read the RFC and make up your own mind, but to me this seems fairly clear-cut - PATCH requests should be processed as partial updates. (NB they are NOT idempotent, unlike PUT.)

EDIT: as pointed out by Eugene in the comments, although PATCH requests are "neither safe nor idempotent as defined by [RFC2616]", they can be made so:

A PATCH request can be issued in such a way as to be idempotent,
which also helps prevent bad outcomes from collisions between two
PATCH requests on the same resource in a similar time frame.
Collisions from multiple PATCH requests may be more dangerous than
PUT collisions because some patch formats need to operate from a
known base-point or else they will corrupt the resource. Clients
using this kind of patch application SHOULD use a conditional request
such that the request will fail if the resource has been updated
since the client last accessed the resource. For example, the client
can use a strong ETag [RFC2616] in an If-Match header on the PATCH
request.

梅窗月明清似水 2024-12-22 13:40:21

您应该使用 RFC-7386“json merge PATCH”中描述的 PATCH 方法。

例如,如果您想更改“a”的值并删除资源中的“f”,例如:

   {
     "a": "b",
     "c": {
       "d": "e",
       "f": "g"
     }
   }

您可以通过发送以下内容来实现:

       PATCH /target HTTP/1.1
       Host: example.org
       Content-Type: application/merge-patch+json

       {
         "a":"z",
         "c": {
           "f": null
         }
       }

You should use method PATCH like described in RFC-7386 "json merge PATCH".

E.g. if you want to change value of "a" and removing "f" in resource like:

   {
     "a": "b",
     "c": {
       "d": "e",
       "f": "g"
     }
   }

You can achive this by sending:

       PATCH /target HTTP/1.1
       Host: example.org
       Content-Type: application/merge-patch+json

       {
         "a":"z",
         "c": {
           "f": null
         }
       }
南汐寒笙箫 2024-12-22 13:40:21

PATCH 与补丁格式一起使用,仅用于文档级补丁(也称为实际表示的差异)。其用于其他目的是可疑和有争议的,并且尚不清楚该方法是否是为非媒体类型用途而设计的。

一般来说,POST 是正确的方法,但您可能希望将资源拆分为多个资源并修改它们。

[为清楚起见进行编辑,因为有些人不阅读评论]

PATCH is to be used with a patch format, for document-level patching only (aka a diff on the actual representation). Its use for other purposes is dubious and debatable, and it's not clear that the method was designed for non-media-type uses.

In general a POST will be the right approach, but you may want to split your resource into multiple resources instead and modify those instead.

[Edited for clarity, as some don't read comments]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文