3

据我了解,如果完全遵循 HTTP 规范,如果您正在执行 PUT 命令,则需要传入资源的所有数据(无论它是否更改),而在执行 PATCH 命令时,您只需传入数据这正在改变。因此,如果我有一个要更改它的每个值的资源,那么 PUT 和 PATCH 命令将具有相同的请求,除了正在使用的 HTTP 动词。

从后端的角度来看,我发现很难找到一个可行的理由来为 PUT 和 PATCH 提供不同的功能。我现在正在构建的 REST API 支持这两种方法,但是它们指向相同的代码,并且代码实际上只是做了一个 PATCH,因为它不请求资源的所有数据,只是请求更改的数据。我想有一个非常好的理由必须为我的所有资源维护一个单独的 PUT 代码路径,因为这增加了代码维护。

当 PATCH 的代码也可以真正执行 PUT 时,是否有任何理由真正为 PUT 和 PATCH 提供不同的功能(除了您应该遵循规范,因为在这种情况下我认为这不是一个很好的理由)?

让 PUT 和 PATCH 只接受资源的更改数据列表是否被认为是不好的做法或可以接受?

4

2 回答 2

3

尽管这两个动词看起来很相似,但在使用其中一个动词时应该考虑到小的、主要是语义上的差异。

  • PUT 是幂等的,PATCH 不是,这意味着一系列相同 PUT 请求的副作用与单个请求的副作用相同。对于 PATCH 来说,情况并非如此,即使它可以强制为幂等。

  • 可以在需要首先了解资源的服务器端状态的方式使用 PATCH。这使得冲突比 PUT 请求更“危险”,因为如果您将操作基于同时已经更改的点/状态,您可能会损坏资源。它代表客户处理此类案件。这对于附加列表项之类的简单操作不是必需的(因为之前的状态无关紧要)。

  • 与 PUT 不同,PATCH 与其修改的资源不属于同一实体。它只描述了某种增量,而不是资源的完整表示。因此,当您说“...如果我有一个资源要更改它的每个值,那么 PUT 和 PATCH 命令将具有相同的请求,除了正在使用的 HTTP 动词”。这也意味着,PATCH 的文档大小不一定比您将与 PUT 一起使用的整个资源数据小。

  • “预计不同的补丁文件格式将

适用于不同类型的资源,并且没有一种格式适用于所有类型的资源。因此,没有实现需要支持的单一默认补丁文档格式。服务器必须确保收到的补丁文档适合 [请求的] 资源类型” - RFC 5789

  • PUT 和 PATCH 之间的比较并不像看起来那么简单,因为您还应该考虑 POST,因为 POST 也可以用于部分修改。

  • 目前,PATCH 只是一个提案,还没有完全/官方标准化。

因此,如您所见,PUT 和 PATCH 之间存在一些差异。有时,能够准确地描述资源的变化可能很重要,因此肯定有适合 PATCH 的用例。我认为提供两者是个好主意,但请注意它们并不完全相同。使用 PATCH 进行实际/部分更新,使用 PUT 更新整个资源。

于 2013-03-13T15:01:16.573 回答
0

PUT 和 PATCH 的区别在于 PUT 要求服务器完全忽略当前状态,而 PATCH 要求服务器在应用有效负载之前考虑当前状态。

您认为没有区别,因为您使用 PATCH 来更新部分表示,传递正在更改的数据。这不是它的工作原理。PATCH 应该使用 diff 格式,明确显示您正在应用更改的当前状态以及结果状态。

例如,在 JSON API 中,您希望email使用补丁更新参数。当前的电子邮件是 myemail@example.com。你不应该只发送:

{'email': 'mynewemail@example.com'}

您必须发送如下内容:

{'old_email': 'myemail@example.com', 'new_email': 'mynewemail@example.com'}

该格式可能由您设计,或者您可以采用标准化的差异格式,具体取决于您的需要。有一个 RFC 提案,要求在这些情况下使用标准JSON 补丁格式。

PUT 的用例是当您需要完全替换某些内容时,完全忽略其中的任何内容(如果有的话)。例如,正在更新其个人资料的用户。无论他做什么,您都希望保留最新版本,而忽略以前存在的任何内容。

PATCH 的用例是当您需要更新某些内容时,同时考虑当前状态,并且仅当它仍然与您上次检查时的状态匹配时。例如,您需要标记某个用户拖欠付款,但在工作开始和实际请求之间,该用户实际付款并且他的个人资料已由您的 API 的另一个客户端更新。如果您通过发送带有 PUT 的完整表示将他的帐户标记为未付款,您将覆盖表明他已付款的数据。如果您使用 PATCH 进行更新,则仅当用户仍处于您之前看到的未付费状态时才会应用请求。

要回答您的最后一个问题,使用 PUT 进行部分更新是不可接受的。PUT 请求是一个完整的替换。

于 2014-06-04T00:13:06.780 回答