Restful从入门到放弃-关于Patch不是幂等的想到的

HTTP Method

首先回顾一下在Restful的API中,我们用到的HTTP方法:

1
2
3
4
5
6
GET /blogs # 获取blog列表
GET /blogs/12 # 查看某个具体的blog
POST /blogs # 新建一个blog
PUT /blogs/12 # 更新blog 12
PATCH /blogs/12 # 更新blog 12
DELETE /blogs/12 # 删除ticekt 12

我们注意到更新操作,有两个方法可以做到:PUTPATCH, 那么它们有什么区别呢?

PUT or PATCH

PATCH比PUT更年轻,在2010年才成为正式的标准,有关于它的介绍中说道,它被用来局部更新某个资源,举个例子:

1
2
3
4
PATCH /users/1 # 更新user 1
{
"nick": "王蛋蛋"
}

把用户ID=1的昵称改为王蛋蛋。它和PUT的区别就在于,PUT必须提供全量的user属性替换原有的服务器资源。而PATCH只会更新提供的字段。

假如user中还有一个version字段用来记录版本,每次PATCH,version++。正因为这样的不可控性 ,所以PATCH被定义为可能是非幂等(idempotent )的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.
PATCH is neither safe nor idempotent as defined by [RFC2616], Section 9.1.

所以,如果是需要全部更新属性,那就是用PUT,如果是局部更新,为了节约带宽,请使用PATCH。在接下来的Restful api设计中,还会提到为什么github不使用PATCH。

关于幂等

哪些叫幂等或/且安全的方法?

安全方法是指不修改资源的 HTTP 方法。譬如,当使用 GET 或者 HEAD 作为资源 URL,都必须不去改变资源。然而,这并不全准确。意思是:它不改变资源的 表示形式。对于安全方法,它仍然可能改变服务器上的内容或资源,但这必须不导致不同的表现形式。

HTTP 幂等方法是指无论调用多少次都不会有不同结果的 HTTP 方法。它无论是调用一次,还是N次都无关紧要。结果仍应相同。再次强调, 它只作用于结果而非资源本身。它仍可能被操纵(如一个更新的 timestamp),提供这一信息并不影响(当前)资源的表现形式。

例如:GET当前时间是幂等的,虽然每次获取的结果不同,但它并没有改变时间这个资源本身,而是只读。所以结果总是一个时间戳。表示形式没有被改变。

1
GET /time # 获取当前时间

还有哪些方法不是幂等的呢?

HTTP MethodIdempotentSafe
OPTIONSyesyes
GETyesyes
HEADyesyes
PUTyesno
POST**nono
DELETEyesno
PATCHnono

可以看到,只有POST和PATCH是非幂等的。

Restful API建议

在构建Restful API时,建议:

  • 一个 API 实现 [PATCH] 必须是原子的。它一定不能出现只 [GET] 到被 [PATCH] 更新了一半的资源。如果不能做到用PUT代替。

  • 明确告诉调用者,API的副作用,是否幂等,以免不必要的疑惑。

题外话

Github Api中,使用了Post代替了Patch,它是这么说的:

VerbDescription
HEADCan be issued against any resource to get just the HTTP header info.
GETUsed for retrieving resources.
POSTUsed for creating resources.
PATCHUsed for updating resources with partial JSON data. For instance, an Issue resource has title and body attributes. A PATCH request may accept one or more of the attributes to update the resource. PATCH is a relatively new and uncommon HTTP verb, so resource endpoints also accept POST requests.
PUTUsed for replacing resources or collections. For PUT requests with no body attribute, be sure to set the Content-Length header to zero.
DELETEUsed for deleting resources.

参考