REST DELETE是否真正满足幂等性要求?

225

DELETE 应该是幂等的。

如果我 DELETE http://example.com/account/123,它将删除该账户。

如果我再次执行,是否期望得到一个404错误,因为该账户已不存在?如果尝试删除从未存在过的账户会怎么样呢?


13
除了答案之外,我建议不要过于关注幂等特性的普遍性:它对交换律和并发请求没有任何作用。例如,同一个“R1”PUT请求的N+1次应该具有相同的效果,但你不知道另一个客户端是否在你的请求中间进行了不同的PUT/DELETE“R2”请求,因此当nR1=R1且mR2=R2时,如果你只从单个客户端的角度来看,获取到交替的“R1”和“R2”请求的东西不一定“看起来”是幂等的。 - Bruno
8个回答

251

幂等性是指请求完成后系统的状态


除了错误问题(见下文)外,在所有情况下,该账户都不再存在。

来自这里

“方法还可以具有‘幂等性’属性,也就是说(除了 错误或过期问题),N > 0个相同请求的副作用与单个请求的副作用相同。GET、HEAD、PUT和DELETE方法共享此属性。另外,OPTIONS和TRACE方法不应具有副作用,因此本质上是幂等的。”


关键点在于“N > 0个相同请求的副作用与单个请求的副作用相同。

你可以期望状态码会有所不同,但这并不影响幂等性的核心概念 - 您可以发送多个请求而无需对服务器状态进行额外更改。


11
副作用 !== 服务器状态。 - wprl
2
@wprl 关于这个“副作用”的真正含义存在争议。它可能是“服务器状态”,也可能是发送给客户端的响应。http://leedavis81.github.io/is-a-http-delete-requests-idempotent/ - Alireza
1
以下是一个关于第二次DELETE返回404实际上可能会改变服务器状态的论点:https://dev59.com/5Ww15IYBdhLWcg3wuuCn#45194747 - Paulo Merson
1
定义“服务器状态”。 - Moe
1
@Moe - 把它看成是持续状态。无论您删除资源的次数如何,不管http结果代码如何,该资源都已从持久状态中消失。这样有帮助吗? - Chris McCauley
显示剩余3条评论

59

幂等(Idempotent)是指请求的效果,而不是您收到的响应代码。

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.2中提到:

除错误或过期问题外,“幂等”方法的副作用与单个请求相同。

虽然您可能会获得不同的响应代码,但发送N+1个DELETE请求到相同资源的效果可以被认为是相同的。


22

摘自我在另一个问题的回答:

历史上,发布于1999年的RFC 2616是HTTP 1.1规范中被引用最多的。不幸的是, 其对幂等性的描述非常模糊,这留给了所有这些争论的空间。但是该规范已被RFC 7231取代。摘自RFC 7231,4.2.2节幂等方法,重点加粗:

如果使用相同方法进行多个相同请求,对服务器的预期影响与单个请求的影响相同,请求方法被认为是“幂等的”。 在本说明书中定义的请求方法中,PUT、DELETE和安全请求方法是幂等的

因此,规范中写明,幂等性完全是关于对服务器的影响。第一个DELETE返回204,然后随后的DELETE返回404,这些不同的状态码并不会使DELETE非幂等。使用这个论点来为随后的204返回辩护是不相关的。

好吧,那么问题就不在于幂等性了。但接下来的一个问题可能是,如果我们仍然选择在随后的DELETE中使用204,这样可以吗?

好问题。这种做法是可以理解的:为了让客户端能够实现其预期的结果,而不必担心错误处理。我认为,在后续的DELETE操作中返回204是一种相对无害的服务器端“善意谎言”,客户端不会立即察觉到其中的差别。所以,有人在实践中这样做,并且仍然运行良好。只需记住这种谎言可能被认为是语义上奇怪的,因为“GET /不存在”的返回值是404,但“DELETE /不存在”则返回204,在这种情况下,客户端将发现你的服务不完全符合 RFC 7231的第6.5.4节404 Not Found规范

但是,RFC 7231暗示的期望方式,即在后续的DELETE操作中返回404,应该本来就不应该成为问题。更多的开发者选择这样做。那很可能是因为任何实现HTTP DELETE(或任何HTTP方法)的客户端都不会盲目地假设结果总是成功的2xx。一旦开发者开始考虑错误处理,404 Not Found可能会是首先想到的错误之一。此时,他/她希望得出结论:忽略404错误对于HTTP DELETE操作来说是语义上安全的。问题得到解决。


1
这是最清晰的答案:204,然后404并且意味着非幂等性,因为它涉及服务器状态而不是返回给用户的内容。 - Oliver
1
很好的后续问题 :) “这样的谎言可以被认为是语义上奇怪的,因为"GET /non-exist"返回404,但"DELETE /non-exist"却给出了204”非常有道理。 - icc97
有趣的是,RFC9110并未将404作为DELETE方法的响应进行提及。但该文档确实指出:“如果使用相同方法进行多个相同请求对服务器的预期影响与单个请求的影响相同,则该请求方法被视为‘幂等’”。事实上,预期的影响和响应是无关的。 - theking2

20
重要的区别是幂等性指的是副作用,而不是所有效果或响应。如果你执行DELETE http://example.com/account/123,那么其效果就是从服务器中删除帐户123,这是唯一的效果,对服务器状态的唯一更改。现在假设您再次执行相同的DELETE http://example.com/account/123请求,服务器将以不同的方式响应,但其状态仍然相同。
这不像DELETE请求决定以不同的方式更改服务器状态,因为帐户不见了,比如删除另一个帐户或留下错误日志。不管怎样,您可以调用相同的DELETE请求一百万次,您可以确信服务器的状态与第一次调用时相同

13

是的。无论响应代码如何。

根据HTTP 1.1最新RFC(我强调),幂等方法因为在客户端能够读取服务器响应之前发生通讯故障时可以自动重复请求而与众不同。例如,如果客户端发送一个PUT请求并且底层连接在接收任何响应之前关闭,那么客户端可以建立一个新的连接并重试幂等请求。它知道重复请求将有相同的预期效果,即使原始请求成功了,但响应可能会有所不同

它明确指出,响应可能会有所不同。更重要的是,它指出了概念的原因:如果一个操作是幂等的,则客户端在遇到任何错误时都可以重复该操作,并知道这样做不会破坏任何东西。否则,客户端将不得不进行其他查询(可能是GET),以查看之前的查询是否有效,才能安全地重复该操作。只要服务器能够提供这样的保证,该操作就是幂等的。引用自另一条评论:

计算幂等性是关于系统的强度。由于事情可能会失效(例如,网络故障),当检测到故障时,您如何恢复?最简单的恢复方法就是重新执行它,但这仅在重新执行是幂等的情况下才有效。例如,discard(x)是幂等的,但pop()不是。这都是关于错误恢复的问题。


这个答案最有道理,应该被采纳。 - Ákos Kovács

11

来自HTTP RFC:

除了错误或过期问题,方法还可以具有“幂等性”的属性,即N > 0个相同请求的副作用与单个请求相同。

请注意,这是“副作用”,而不是“响应”。


7

假设我们需要管理由idnamecity表示的足球队伍。

{
    id: "1",
    name: "manchester united",
    city : "manchester "
}

DELETE是幂等的意思是,如果您多次调用DELETE /team/1,系统的状态保持不变(实际上第一次调用DELETE /team/1会删除团队)。换句话说,因为重复调用DELETE不会更改系统状态,所以DELETE是幂等的。

同样地,我们也可以说PUT是幂等的。 想象一下,您执行了多个PUT

PUT /team/1
{
    id: "1",
    name: "liverpool",
    city : "liverpool"
}

重复调用这样的PUT请求总是有相同的效果(团队1将是利物浦)。

显然,GET请求也是幂等的。


1

我认为也是这样,404 - 账户不存在。

你可以说400 - 错误的请求。但从REST的角度来看,您请求执行操作的对象不存在。这就转化为404。


3
生成400响应代码需要知道之前存在的对象,这与RESTful原则不符。 - annakata
1
@annakata,400并不是用于曾经存在的资源(也许您想到了410 / Gone),而是用于错误请求"由于格式不正确,服务器无法理解请求。" - Bruno
3
我知道你的意思,原帖中已经提到了它。 - annakata
2
我认为200就可以了。你希望服务器的状态是该账户已经消失了。哪个请求实际上让它消失了,这有关系吗?在第二个请求中它仍然消失了,服务器状态没有改变。 - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接