REST中的PUT/DELETE是否自动具有幂等性?

28

我正在学习有关REST、PUT/DELETE的知识,我已经了解到这三种方法都是幂等的,也就是说多次请求不会改变服务器的状态。

在使用XMLHttpRequest时,重复的PUT/DELETE请求是否会离开web浏览器?换句话说,服务器是否会为每个PUT请求更新同一数据库记录,还是重复请求会被自动忽略?

如果是的话,使用PUT或DELETE与仅使用POST有什么不同?

我读过一篇文章,建议使用RESTful Web服务。有没有什么特别的原因导致HTML5表单不支持PUT/DELETE方法呢?


5
如果接收请求的服务器真正符合RESTful并以幂等方式实现,那么没有任何东西是自动的。如果您必须提问,请在http://programmers.stackexchange.com上提问,我不会将此作为答案写入StackOverflow,因为这与主题无关。 - Dan Grossman
1
您可能还想查看以下答案: https://dev59.com/-m855IYBdhLWcg3w5IrZ https://dev59.com/HHRB5IYBdhLWcg3wa2q2 - Deep Kapadia
4个回答

56

REST仅仅是用于数据访问和操作的设计结构,并没有强制规定服务器必须如何响应数据请求。

话虽如此,通常情况下REST的PUTDELETE请求会按照以下方式进行:

DELETE /item/10293
或者
PUT /item/23848
foo=bar
fizz=buzz
herp=derp

这些请求与特定ID相关联。因此,如果告诉服务器删除相同的ID 15次,除非有某种重新编号,否则最终结果基本上与调用一次相同。

使用PUT请求,告诉服务器将特定项更新为特定值也会导致相同的结果。

一个命令不是幂等的情况通常涉及某种相对值:

DELETE /item/last

调用该函数15次可能会删除15个项目,而不是相同的最后一个项目。使用HTTP正确的替代方法可能如下所示:

POST /item/last?action=delete

REST不是官方规范,只是一个具有一些常见特性的结构。有许多实现RESTful结构的方法。


至于HTML5表单是否支持PUTDELETE,这取决于浏览器是否开始支持不同的方法,而不是规范本身。如果所有浏览器都开始实现不同的表单提交方法,我相信它们会被添加到规范中。

随着网络的发展,一个好的RESTful实现也可能会在任何情况下包含某种形式的AJAX,所以对我来说似乎大体上是不必要的。


2
REST不是官方规范,但它提醒我们不要通过添加新方法或在事务中添加状态而偏离HTTP。因此,像DELETE /item/last这样的请求是不幂等的,因此不应使用。例如,浏览器在点击“返回”时会再次发送请求而不询问用户确认。此外,POST /item/last?action=delete似乎不是一个好主意,你怎么能保证你删除的是你想要删除的资源呢? - Ruan Mendes
@JuanMendes,说得好。实际上我在回答另一个问题时也提到了这个问题,并且我应该修改一下这个答案以反映更好的方法。 - zzzzBov
根据RFC2616,GET、HEAD、PUT和DELETE方法是幂等的。因此,您不能像使用GET /item/last或PUT /item/last一样使用DELETE /item/last。原因是中间服务器应该能够在失败或无响应的情况下重复DELETE请求,而不会破坏应用程序逻辑。 - alpav
2
所以你没有被禁止...这是编程,你可以做任何你想做的事情,因为没有人能阻止你。这并不意味着/item/last的概念是一个好主意,但问题是关于这个行为是否自动化,而它显然不是。 - zzzzBov
这个答案非常有帮助。我曾经对PUT方法的定义感到非常困惑,因为我无法理解HTTP给PUT方法规定了什么规则来确保其幂等性。现在我知道没有什么是幂等的,而是由程序员编写控制器中调用的方法的方式来确保幂等性。 - Arun Raaj
一个问题。如果没有指定ID的PUT请求怎么办?它会像POST一样工作,每次调用此端点时都会创建一个新对象,对吗?我知道这取决于服务器上的实现方式,但我想知道应该如何实现。 - Piotr Filochowski

7
当使用XMLHttpRequest时,重复的PUT/DELETE请求是否会离开Web浏览器?是的,确实如此。幂等性只是一种约定,并没有强制执行。无论您进行重复请求与否,它都将被执行。 换句话说,服务器是否会为每个PUT请求更新相同的数据库记录,还是会自动忽略重复请求?如果符合REST规范,应该会更新相同的数据库记录两次,例如运行UPDATE user SET name = 'John'两次。但它具体会做什么或不做什么取决于它的实现方式。 PUT或DELETE与POST的区别仅在于惯例。在网站代码中,PUT和DELETE请求可能与POST请求处理方式有所不同。 我读过一篇文章,建议使用RESTful Web服务是未来的方向。HTML5表单为什么不支持PUT/DELETE方法?老实说,我不太确定。您可以通过使用名为_method或类似名称的隐藏字段并将其设置为DELETE或PUT来解决这个问题,然后在服务器端处理它。

1
XMLHttpRequest即使HTML 5规范不支持,仍将支持PUT/DELETE。这将是另一种解决方案。我猜这也取决于浏览器对规范的认可程度。 - Deep Kapadia
@Deep:是的,但从技术上讲,这与他所问的HTML表单无关:S - Andreas Bonini
4
幂等性不仅是一种约定,它是服务器向客户端(以及中介)作出的承诺。然而,作为服务的实现者,您有责任履行(或打破)这个承诺。虽然没有强制执行幂等性,但中介(例如代理)会基于该承诺进行假设,如果不符合,可能对您的服务或客户造成不良后果。与POST的唯一区别在于,POST不对安全性或幂等性作出任何承诺,因此代理不会对此进行任何假设。 - jhericks
回复:“重复的PUT/DELETE请求是否会离开Web浏览器” - 它们不应该由Web浏览器本身发出超过一次。如果TCP堆栈向浏览器返回错误,则应将其报告给JavaScript代码,代码需要尝试再次发送它,这是符合规范的安全操作。 - alpav

2

PUT操作是幂等但不是安全的操作。如果PUT操作成功,重复此操作将不会插入重复记录。在网络故障错误后,请验证条件标头(如If-unmodified-since和/或if-match),然后重复PUT操作。在出现4XX或5XX错误代码时不要重复操作。


0

REST旨在建立关于使用HTTP方法的语法约定;每个后端都可以自由实现任何内容,开发人员可以打破约定,但如果被其他未参与开发的人使用,将会造成不必要的混乱。

对于DELETE操作,如果您删除了某个带有ID的项目,则服务器应该响应其已被删除;如果再次删除,则不再存在,因此服务器响应“已删除”,这也是很好的,因为您的目的已经达到。PUT操作也是如此,因为您提供了资源的新状态,即尚未更新的状态;如果已经更新,任务完成,对于客户端也是一样。


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