PHP,DDD,CQRS,Event Sourcing,Kubernetes,Docker,Golang

0%

RESTful接口中的PATCH和PUT

头图

RESTful接口现在很普遍,但是如果你作为一名web开发者,你应该知道对于不同的情况如何去选择一个最合适的HTTP方法有点困难。

对于开发REST接口来说,更新一个资源是常见的事,这里有两个开发者经常使用的HTTP方法:PUTPATCH,一般你会选择哪一个?

这两个方法看起来作用相同,都是更新一个服务的资源,但它们底层确是完成不同的事情。本篇文章将帮助你理解PUT和PATCH请求之间的区别,以便你可以设计一个专业的生产级别的API。

PUT VS PATCH

PUT和PATCH之间的区别

REST API中PUT和PATCH的主要区别在于PUT通过替换整个实体来完成更新操作,而PATCH仅仅更新你提供给它的字段,PATCH不会改变其他的任何值。

如果你使用PUT方法,那么你更新的资源的整体内容都会被更新。这依赖于服务端的实现,在大多数的实现中,这意味着你没有提供的字段将会被覆盖为空值。PATCH方法只更新你提供的单独的几个字段内容,而不会去改变其他已经存在的字段内容。

PUT需要消耗更多的带宽,因为它需要你提供完整的资源内容,因此PATCH诞生了,为了减少带宽的消耗。

PUT PATCH
部分更新
带宽消耗
创建一个资源
幂等性
安全性

PUT

HTTP的PUT方法被用来创建一个资源替换一个旧的资源。IETF定义PUT方法为”only allowing a full replacement of a document”(只允许对文档的完整替换)。

客户端必须在请求body内发送一个完整的实体内容。

  • 客户端提供一个资源ID
  • 如果资源存在,将其替换为新的数据
  • 如果资源不存在,则创建一个新的

使用PUT的优势

  • 我们无需在更新一个资源后再重新获取这个资源内容,因为PUT发送的内容就是整个资源实体内容。
  • 如果我们发送所有字段并对不包含对已存在字段的增量修改,那么我们总是可以覆盖整个实体。这意味着我们的API客户端只需要实现一个PUT方法就可以了,而不需要实现多个部分更新的方法。
  • 如果资源不存在,那么会进行新建一个资源,这有时会比较有用。

PATCH

PATCH用来对一个已经存在的资源进行修改或新增内容。PUT方法一次性创建整个资源实体,而PATCH只更新所需要更新的字段。

PATCH方法在2010年被创建,用来应对PUT方法无法对部分内容进行更新的缺陷。

Paypal API uses PATCH to update an order

PATCH的优势

  • 客户端在发送更新请求之前无需知道资源的完整的状态
  • 对于每个修改资源的请求,PATCH方法可以更方便的看出其更新的意图,这个优势在debug日志的一些情况下很有用,使用PATCH而不是PUT来关注资源的更新会更加容易,因为请求body体的内容带有非常明显的意图。
  • PATCH由于允许资源的部分内容更新,因此很节省带宽,当更新大的对象时PATCH比PUT会更有效率。

一般性的更新和意图

当选择PATCH还是PUT时,考虑客户端和服务端的实现很重要。

从客户端的角度来看,PATCH看起来很好用,因为其只更新你需要更新的部分。但是当你从服务端的角度看时,事情就会变得比较复杂。

例如:

1
2
3
4
PATCH /orders/533
{
"total": 8.34
}

在这个请求中,我们只想要更新total字段,意味着服务端的实现不应该影响到其他字段。但是服务端开发者现在需要知道客户端可能更新的所有字段。

我们称这个更新的“意图”在PATCH请求中并不是很明显。为了克服这个问题,我们可以使用一个称为JSON PATCH的特性,其可以定义更新的意图。

一个“意图”可以将你想要对资源实体的修改展示出来,对于基于属性的patch请求,你可以使用HTTP header来表达你对更新的意图。

1
2
3
4
5
6
PATCH /orders/533
[

{ "op": "replace", "path": "/total", "value": "8.34" }

]

根据RFC6902,可支持的意图有addremovereplacemovecopytest

JSON PATCH使得更新一个资源更加简单了一点。客户端定义一个更新意图,服务端则根据定义的内容来对资源对象进行更新。

幂等原则

RESTful架构都是和幂等操作有关的。一个幂等操作无论什么时候执行,都只会产生相同的结果,非幂等操作则会导致不同的结果。

幂等方法的定义适用于资源而不是结果。如果你调用了相同的幂等操作两次,则该方法两次产生的结果应该是相同的。幂等操作不应该具有副作用,这里的副作用指的是在幂等操作方法之外任何状态的改变。

PUT是一个幂等操作而PATCH不是,这是因为PUT能修改资源的整个内容而不是部分的字段。

PATCH方法不是幂等操作,是因为若资源从未被patched过,则其修改的数据可能会导致不同的状态。PATCH应该只能用于修改一个已经存在的资源。

并发更新

当使用PATCH更新资源时,在请求中包含一些条件来防止其他人同时更新这个资源是一个不错的主意。

ETagHTTP响应头是一个ID,用来识别资源的特定版本。

If-MatchETag头一起使用时,将有助于在客户端尝试更新一个资源时来确定是否能更新。

总结

如果你需要在PATCH和PUT之间做选择,请考虑它们之间的区别:

  • 使用PUT请求,会修改整个资源,而使用PATCH请求,只会修改指定的资源的部分内容。
  • 当我们使用PUT请求时,我们将请求发送的整个实体视为修改的版本,并替换掉服务端上已存在的版本。而使用PATCH请求时,请求的实体包含了一组指令,来描述了如何修改服务端上的现有资源,以产生一个新的版本。

FAQ

  • PUT和PATCH之间的区别

在REST API中PUT和PATCH的区别是,PUT通过替换整个资源实体来达到更新的目的,而PATCH只更新你给定的字段。

  • PATCH请求中含有请求Body吗?

有,PATCH请求中含有请求体Body来指示修改或者添加一些内容到已经存在的资源上。

  • PATCH和PUT需要返回哪种HTTP状态码?

成功的PATCH请求应该返回2XX范围的状态码。两个最常用的是204(没有响应的数据)和200(有响应的数据)。成功的PUT请求也应该返回2XX范围的状态码,同样最常用的也是204和200,如果想要修改的资源还不存在,并且创建新的资源成功,服务端需要响应201(Created)状态码。

  • 能否同时使用PUT和PATCH?

可以,因为PUT和PATCH具有不同的目的,因此你可以都使用。

  • 对于客户端来说用PATCH还是PUT更容易?

这要看具体的情况的,但是PATCH通常对客户端来说更容易,因为客户端想要修改资源内容的话不需要提前加载获取整个资源。

  • PATCH是否可以被用在只读资源上?

可以,如果你只是想在JSON PATCH使用”test”意图做一些测试,那你可以使用,你不需要修改任何资源。

  • 为什么PUT是幂等的而PATCH不是?

PUT幂等是因为调用它一次或多次所产生的效果是一样的。而PATCH不幂等是因为每次调用会产生不同结果。例如,我们想要使用PUT更新订单的总价total字段,我们需要指定值为¥22.9,而如果使用PATCH,我们可能会发送“increase 10.4”增加10.4元的指令,当订单总价为12.5元时,我们通过PATCH会使得订单状态更新为22.9元,但如果当前订单总价不是12.5元,那么就会导致不一样的结果。

  • PATCH能否做到幂等?

也是可以的,例如你发送的指令是"set":"price":50,意味着将价格设置为50元,这样就具有幂等性了。

  • PUT请求安全吗?

不安全,只有不会改变服务器资源状态的HTTP请求才是安全的,只读的HTTP操作才是安全的。

  • PATCH能创建一个资源吗?

根据RFC 5789应该可以,但实践上是不行的

原文: https://josipmisko.com/posts/patch-vs-put-rest-api