为何 HTTP PATCH 方法不是幂等的及其延伸

幂等性

首先来看什么是幂等性,根据 rfc2616(Hypertext Transfer Protocol -- HTTP/1.1) 文档第 50 页底部对 Idempotent Methods 的定义:html

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.数据库

翻译过来也就是:相同的请求执行屡次和执行一次的反作用是同样的后端

段落接下来就给出了具备幂等性的方法:api

The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.服务器

能够看出,GETHEADPUTDELETEOPTIONSTRACE 方法都是幂等的。app

PUT 和 PATCH

根据约定( Convention ),PUT 方法用于更新数据,PATCH 方法也用于更新数据,为何 PUT 方法是幂等的而 PATCH 方法不是幂等的呢?咱们继续研究文档(第54页):ide

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI.post

PUT 方法将请求所包含的实体存储在所提供的 Request-URI 下。若是该 URI 指代一个已经存在的资源,那么请求中的实体应该被视为保存在原服务器上的实体的修改版本。若是 Request-URI 没有指向一个现有资源,而且该 URI 能够被发送请求的用户代理定义为新资源,则原服务器可使用该 URI 来建立资源。this

这里说的很明白了,PUT 用作更新操做的时候是提交一整个更新后的实体,而不是须要修改的实体中的部分属性。当 URI 指向一个存在的资源,服务器要作的事就是查找并替换。翻译

接下来看 PATCH(PATCH 方法在原文档中没有找到相关描述,后来发如今另外一个 RFC 里面 - RFC5789):

The PATCH method requests that a set of changes described in the request entity be applied to the resource identified by the Request-URI. The set of changes is represented in a format called a "patch document" identified by a media type. If the Request-URI does not point to an existing resource, the server MAY create a new resource, depending on the patch document type (whether it can logically modify a null resource) and permissions, etc.

PATCH 方法请求将一组描述在请求实体里的更改应用到 Request-URI 标志的资源。这组更改以称为 "补丁文档" 的格式(该格式由媒体类型标志)表示,若是 Request-URI 未指向现有资源,服务器可能根据补丁文档的类型(是否能够在逻辑上修改空资源)和权限等来建立一个新资源。

因此能够知道 PATCH 请求中的实体是一组将要应用到实体的更改,而不是像 PUT 请求那样是要替换旧资源的实体,可是这并无解决 PATCH 方法为何不是幂等的问题。不着急,继续读,接下来就给出了 PUT 和 PATCH 的区别:

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 PATCH method affects the resource identified by the Request-URI, and it also MAY have side effects on other resources; i.e., new resources may be created, or existing ones modified, by the application of a PATCH.

PUT 和 PATCH 请求的区别体如今服务器处理封闭实体以修改 Request-URI 标志的资源的方式。在一个 PUT 请求中,封闭实体被认为是存储在源服务器上的资源的修改版本,而且客户端正在请求替换存储的版本。而对于 PATCH 请求,封闭实体中包含了一组描述当前保留在源服务器上的资源应该如何被修改来产生一个新版本的指令。PATCH 方法影响由 Request-URI 标志的资源,并且它也可能对其余资源有反作用;也就是,经过使用 PATCH,新资源可能被创造,或者现有资源被修改。

以上就是答案。能够理解为,PATCH 请求中的实体保存的是修改资源的指令,该指令指导服务器来对资源作出修改,因此不是幂等的。
可能有点抽象,打个比方:对于存在服务器中的 A 对象有个属性 B 为 1,若是要修改 B 属性为 3,则 PUT 请求是直接将修改过 B 属性的整个新对象发送给服务器查找并替换。而 PATCH 请求是在实体中包含指令 --- 将 A 对象中 B 属性的值加 2,那么若是该请求被执行屡次的话,B 属性就可能不为 3 了,而 PUT 请求不论执行多少次,B 属性永远都是 3,因此说 PUT 方法是幂等的,而 PATCH 方法不是幂等的。

PUT 和 POST

在看请求相关的帖子的时候,偶尔也会看见争论说使用 PUT 来新增资源,使用 POST 来修改资源,或者说这两个方法差异不大,不必这么明确分工。上文也提到了 PUT 方法的 URI 指向的资源不存在的时候也能够建立新资源。那到底怎么用,都写到这里了继续是用文档来讲话,有关 POST 方法的说明:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. POST is designed to allow a uniform method to cover the following functions:

  • Annotation of existing resources;
  • Posting a message to a bulletin board, newsgroup, mailing list or similar group of articles;
  • Providing a block of data, such as the result of submitting a form, to a data-handling process;
  • Extending a database through an append operation.

The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI. The posted entity is subordinate to that URI in the same way that a file is subordinate to a directory containing it, a news article is subordinate to a newsgroup to which it is posted, or a record is subordinate to a database.

POST 方法用于请求源服务器接受请求中的实体做为 Request-URI 所标志的资源的新下级。 POST 方法旨在容许一个统一的方法来涵盖如下功能:

  • 现有资源的注释;
  • 在公告栏,新闻组,邮件列表或相似文章组中发布消息;
  • 提供数据块,例如提交表单的结果,数据处理过程;
  • 经过追加操做扩展数据库。

POST方法执行的实际功能由服务器肯定,一般依赖于 Request-URI。 发布的实体从属于该 URI,其方式与文件从属于包含它的目录相同,新闻文章从属于发布它的新闻组,或者记录从属于数据库。

加黑的第一句话是否是很熟悉,用 RESTful API 实现先后端交互接口的朋友看到这里应该就清楚了。这也是为何 POST /api/articles 在 RESTful 中被建议用来建立文章而不是更新文章的缘由。此外,POST 请求不是幂等的,觉得着若是把它用来看成资源更新操做,会创造多个相同的资源,这是更新操做不但愿产生的反作用,因此仍是用 POST 新增资源,PUT 更新资源吧。

固然,这些都是约定( convertion ) 而不是规定( standard ),若是你就是喜欢用 PUT 新建资源,POST 来修改资源,那我只能说对不起让你花这么长时间看篇文章了,仅仅使用 GET 和 POST 完成全部操做也还大有人在😄😄。

相关文章
相关标签/搜索