为什么PATCH方法不是幂等的?


48

我对此很纳闷。

假设我有一个user资源idname字段。如果我想更新一个字段,我可以像这样对资源进行PATCH请求

PATCH /users/42
{"name": "john doe"} 

然后应用程序将更新用户42的名称。

但是,如果我重复此请求,结果会有所不同吗?

根据RFC 5789

PATCH既不安全也不具有幂等性


如果在两次调用之间有人请求更新用户42,该怎么办{"name": "bendjamin franklin"}
2014年

@gnat是否对PUT方法也没有类似的论点,而被认为是幂等的?(见goo.gl/t24ZSJ
mattecapu

“ PUT具有幂等的语义,因此可以安全地用于绝对更新(即,我们将资源的整个状态发送到服务器),但不能用于相对更新(即,仅将对资源状态的更改发送给服务器,因为那样会违反它的语义...”(POST和PUT请求–仅仅是约定吗?
t

1
显然……但是您可以说PUT不是幂等的,因为在两个相等的请求之间,第二个客户端可以在两个请求之间发出第三个请求。但是由于我们不在乎以前的数据,所以这不是问题。相同的参数适用于PATCH请求。
mattecapu 2014年

2
我可以随意添加对相关规范的引用,因为我认为这在此问题的上下文中非常相关。
皮特2014年

Answers:


34

PATCH请求可以是幂等的,但不是必须的。这就是为什么它被描述为非幂等的原因。

PATCH是否可以是幂等的,在很大程度上取决于如何传达所需的更改。
例如,如果补丁格式为{change: 'Name' from: 'benjamin franklin' to: 'john doe'},则第一个请求之后的任何PATCH请求都会具有与第一个请求不同的效果(失败响应)。
非等幂性的另一个原因可能是,将修改应用于原始资源以外的其他内容可能会使资源无效。如果您多次应用更改,情况也会如此。


3
我不理解最后一段,您能否举一个例子说明“对原始资源以外的其他内容进行修改会使资源无效”,这与将更改多次应用于同一资源有何关系?
罗宾·格林

3
@RobinGreen:假定资源以XML表示,并且要求最多有一个<name>元素。如果PATCH将<name>元素添加到最初不包含元素的资源中,则两次应用PATCH(或将其应用到已经包含的资源中<name>)会使资源无效,因为它会突然包含两个<name>不允许的元素这样的资源。
Bart van Ingen Schenau 2015年

13
您提供的第一个示例与IMHO无关,因为它是幂等的。具有幂等性的DELETE的示例,第一个请求:资源存在但已被删除(返回2xx),第二个请求:资源不存在,并且在请求之后仍然不存在,返回4xx。服务器状态没有改变,因此幂等。在您的示例中,第一个请求:从BenFra到JohDoe的PATCH,资源名称是BenFra,但现在是JohDoe(返回2xx),第二个请求:从BenFra到JohDoe的PATCH,资源名称是JohDoe,现在仍然是JohDoe(返回4xx)。因此,这并不表示PATCH可以是非幂等的。
sp00m

此处有更多详细信息:stackoverflow.com/q/4088350/1225328
sp00m

7

我认为,当RFC中的PATCH不是幂等时,答案很明确:

在某些情况下,补丁程序格式不需要从已知的基点开始运行(例如,将文本行附加到日志文件中,或者将不冲突的行附加到数据库表中),在这种情况下,不需要对客户端请求进行同样的处理。

由于RFC指定补丁包含对资源的一些“一般更改”,因此我们不仅仅应进行典型的字段替换。如果资源用于计数器,则patch可以请求其增加,这显然不是idempotet。


2

PATCH请求描述了将应用于资源的一组操作,如果将同一组操作两次应用于同一资源,则结果可能会不同。这是因为定义操作取决于您。换句话说,您必须定义合并规则

请记住,PATCH请求可以用于修补许多不同格式的资源,而不仅仅是JSON。

因此,如果将合并规则定义PATCH为幂等,请求可以是幂等的

幂等示例:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  age: 33
}

// New resource
{
  name: 'Tito',
  age: 33
}

非等幂示例:

// Original resource
{
  name: 'Tito',
  age: 32
}

// PATCH request
{
  $increment: 'age'
}

// New resource
{
  name: 'Tito',
  age: 33
}

在第二个示例中,我使用了“ Mongo like”语法,用于增加属性。显然,这不是幂等的,因为多次发送相同的请求每次都会导致不同的结果。

现在您可能想知道使用这种组合语法是否有效。根据标准,它是:

PUT和PATCH请求之间的差异反映在服务器处理封闭实体以修改由Request-URI标识的资源的方式上。在PUT请求中,封闭的实体被视为原始服务器上存储的资源的修改版本,并且客户端正在请求替换存储的版本。但是,对于PATCH,封闭的实体包含一组指令,这些指令描述了应如何修改当前驻留在源服务器上的资源以产生新版本。

您可能还想知道以这种方式使用请求是否很麻烦PATCH,并且许多人认为它们不是,这是一个很好的答案,其中包含有关该问题的大量评论。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.