HTTP 幂等性

HTTP 幂等性

RFC 对于 Idempotent Methods 的定义如下:

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.

翻译过来就是,相同的请求执行多次和执行一次的副作用是一样的

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.

  • GET:获取资源,不管调用多少次接口,结果都不会改变,所以是幂等的
  • POST:调用多次,每次都会产生新的资源,不满足幂等性
  • PUT:用实体部分的数据替换到服务器的资源,多次调用只会产生一次影响,满足幂等性
  • PATH:请求中的实体是一组将要应用到实体的更改,而不是像 PUT 请求那样是要替换旧资源的实体,有可能是非幂等的
  • DELETE:调用一次和多次对资源产生影响是相同的,满足幂等性

PUT 和 PATCH

先看下 RFC 对两个方法的定义:

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.

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

PUT 用于更新操作时是提交一整个更新后的实体,而不是需要修改的实体中的部分属性。当 URI 指向一个存在的资源,服务器要做的事就是查找并替换。

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 请求那样是要替换旧资源的实体

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 方法不是幂等的。

POST 和 PUT

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,其方式与文件从属于包含它的目录相同,新闻文章从属于发布它的新闻组,或者记录从属于数据库。

POST 方法用于请求源服务器接受请求中的实体作为 Request-URI 所标志的资源的新下级。这也是为什么 POST /api/articles 在 RESTful 中被建议用来创建文章而不是更新文章的原因。所以还是用 POST 新增资源,PUT 更新资源吧。当然,这些都是约定( convertion ) 而不是规定( standard ),也可用 PUT 新建资源,POST 来修改资源。