为了账号安全,请及时绑定邮箱和手机立即绑定

REST API-带有实际示例的PUT与PATCH

REST API-带有实际示例的PUT与PATCH

摇曳的蔷薇 2019-12-07 13:12:15
首先,一些定义:PUT在9.6节RFC 2616中定义:PUT方法请求将封闭的实体存储在提供的Request-URI下。如果Request-URI引用了已经存在的资源,则应将封闭的实体视为驻留在源服务器上的实体的修改版本。如果Request-URI没有指向现有资源,并且请求用户代理能够将该URI定义为新资源,则原始服务器可以使用该URI创建资源。PATCH在RFC 5789中定义:PATCH方法请求将在请求实体中描述的一组更改应用于由Request-URI标识的资源。同样根据RFC 2616,第9.1.2节 PUT是幂等的,而PATCH不是。现在让我们看一个真实的例子。当我/users对数据进行POST {username: 'skwee357', email: 'skwee357@domain.com'}且服务器能够创建资源时,它将以201和资源位置(假设/users/1)响应,并且对GET的下一次调用/users/1将返回{id: 1, username: 'skwee357', email: 'skwee357@domain.com'}。现在说我要修改我的电子邮件。电子邮件修改被视为“一组更改”,因此,我应该/users/1使用“ 补丁文档 ”来进行补丁。就我而言,这将是一个json {email: 'skwee357@newdomain.com'}。然后,服务器返回200(假设允许)。这使我想到第一个问题:补丁不是幂等的。它在RFC 2616和RFC 5789中是这样说的。但是,如果我发出相同的PATCH请求(使用我的新电子邮件),则会得到相同的资源状态(将我的电子邮件修改为请求的值)。为什么PATCH不那么幂等?PATCH是一个相对较新的动词(2010年3月引入RFC),用于解决“修补”或修改一组字段的问题。在引入PATCH之前,每个人都使用PUT来更新资源。但是在引入PATCH之后,让我感到困惑的是,PUT是用来做什么的?这使我想到了第二个(也是主要的)问题:PUT和PATCH之间的真正区别是什么?我读过某处PUT可能会用来替换特定资源下的整个实体,因此应该发送完整的实体(而不是像PATCH那样发送一组属性)。这种情况的实际实际用途是什么?您何时要替换/覆盖特定资源URI下的实体,为什么不将这种操作视为更新/修补实体?我在PUT上看到的唯一实际用例是在集合上发布PUT,即/users替换整个集合。引入PATCH之后,在特定实体上发布PUT毫无意义。我错了吗?
查看完整描述

3 回答

?
慕娘9325324

TA贡献1783条经验 获得超4个赞

尽管已经彻底地回答了OP关于PUT和PATCH之间的区别的问题,但其对为什么PATCH不等幂的问题的回答并不十分正确。


为了显示PATCH为什么不是幂等的,它有助于从幂等的定义开始(来自Wikipedia):


幂等一词用于更广泛地描述一种操作,如果执行一次或多次,将产生相同的结果。幂等函数是具有以下性质的函数f(f(x))= f(x)任何值x。


用更易访问的语言,幂等的PATCH可以定义为:用补丁文档对资源进行补丁之后,对具有相同补丁文档的相同资源的所有后续PATCH调用都不会更改该资源。


相反,非等幂运算是其中f(f(x))!= f(x)的情况,对于PATCH,可以将其表示为:用补丁文档对资源进行PATCH之后,随后的PATCH用同一补丁文件确实会更改资源。


为了说明非幂等的PATCH,假设有一个/ users资源,并且假设调用GET /users返回了一个用户列表,当前:


[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" }]

假定服务器允许PATCHing / user,而不是像OP的示例中那样PATCHing / users / {id}。让我们发出以下PATCH请求:


PATCH /users

[{ "op": "add", "username": "newuser", "email": "newuser@example.org" }]

我们的补丁文档指示服务器将一个名为的新用户添加到用户newuser列表中。第一次调用此函数后,GET /users将返回:


[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },

 { "id": 2, "username": "newuser", "email": "newuser@example.org" }]

现在,如果我们发出与上述完全相同的 PATCH请求,会发生什么?(就本例而言,假设/ users资源允许重复的用户名。)“ op”为“ add”,因此将新用户添加到列表中,随后GET /users返回:


[{ "id": 1, "username": "firstuser", "email": "firstuser@example.org" },

 { "id": 2, "username": "newuser", "email": "newuser@example.org" },

 { "id": 3, "username": "newuser", "email": "newuser@example.org" }]

即使我们针对完全相同的端点发出了完全相同的 PATCH ,/ users资源也再次发生了变化。如果我们的PATCH是f(x),则f(f(x))与f(x)不同,因此,该特定PATCH不是幂等的。


尽管不能保证 PATCH是幂等的,但是PATCH规范中没有任何内容可以阻止您对特定服务器进行幂等的所有PATCH操作。RFC 5789甚至预期幂等PATCH请求的优点:


可以以幂等的方式发出PATCH请求,这也有助于防止在相似的时间范围内同一资源上的两个PATCH请求之间的冲突导致不良结果。


在Dan的示例中,他的PATCH操作实际上是幂等的。在该示例中,/ users / 1实体在我们的PATCH请求之间进行了更改,但不是因为我们的PATCH请求而发生的;而是 实际上是邮局的其他补丁文档导致了邮政编码的更改。邮局的不同PATCH是不同的操作;如果我们的PATCH为f(x),则邮局的PATCH为g(x)。幂等性指出f(f(f(x))) = f(x),但不做任何保证f(g(f(x)))。


查看完整回答
反对 回复 2019-12-07
  • 3 回答
  • 0 关注
  • 874 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号