HTTP PUT和DELETE的幂等性

时间:2012-10-29 15:58:54

标签: api http rest asp.net-web-api

所以HTTP规范说HTTP PUT和DELETE应该是幂等的。这意味着,对具有相同正文的同一URL的多个PUT请求不应导致服务器上的其他副作用。多个HTTP DELETE也是如此,如果将2个或更多DELETE请求发送到同一个URL,则第二个(或第三个等)请求不应返回指示资源已被删除的错误。

然而,在处理完DELETE之后PUT对URI的请求怎么办?它应该返回404吗?

例如,请考虑按以下顺序执行以下请求:

  • POST / api / items - 创建item资源,返回HTTP 201和URI / api / items / 6
  • PUT / api / items / 6 - 更新与item#6
  • 相关的数据
  • PUT / api / items / 6 - 只要请求体与之前的PUT相同,就没有副作用
  • DELETE / api / items / 6 - 删除item#6并返回HTTP 202
  • DELETE / api / items / 6 - 没有副作用,并且还返回HTTP 202
  • GET / api / items / 6 - 现在返回404
  • PUT / api / items / 6 - 这里会发生什么? 404? 409?别的什么?

那么,如果PUT与获取和返回404一致,或者@CodeCaster建议,那么409会更合适吗?

2 个答案:

答案 0 :(得分:11)

  

RFC 2616,第9.6节,PUT:

     

POST和PUT请求之间的根本区别在于      反映在Request-URI的不同含义中。一个中的URI      POST请求标识将处理随附的资源      实体。该资源可能是一个数据接受过程,一个网关      一些其他协议,或接受注释的单独实体。      相反,PUT请求中的URI标识所包含的实体      使用请求 - 用户代理知道URI的用途和      服务器不得尝试将请求应用于其他资源。

  

如果无法使用Request-URI创建或修改资源,则应该给出适当的错误响应,以反映问题的性质。

因此定义'适当'是看400系列,表明存在客户端错误。首先,我将消除不相关的:

  • 400错误请求:由于格式错误,服务器无法理解该请求 语法。
  • 401 Unauthorized :请求需要用户身份验证。
  • 402需要付款:此代码留作将来使用。
  • 406不可接受:请求[...]标识的资源不可接受 根据请求中发送的接受标头。
  • 407需要代理身份验证:此代码[...]表示 客户端必须首先使用代理进行身份验证。
  • 408请求超时:客户端在服务器准备等待的时间内未生成请求。
  • 411长度要求:服务器拒绝接受没有定义内容的请求 - 长度。

那么,我们可以使用哪些?

  

403 Forbidden

     

服务器理解请求,但拒绝履行请求。      授权无效,请求不应重复。

这个描述实际上非常适合,尽管它通常用于与权限相关的上下文中(如:你可能不会......)。

  

404 Not Found

     

服务器未找到与Request-URI匹配的任何内容。没有      指示该条件是暂时的还是      常驻。如果服务器应该使用410(Gone)状态代码      通过一些内部可配置的机制,知道一个旧的      资源永久不可用,没有转发地址。      此状态代码通常在服务器不希望时使用      明确说明请求被拒绝的原因,或者没有其他请求      回应是适用的。

这也是,尤其是最后一行。

  

405 Method Not Allowed

     

请求行中指定的方法不允许使用      Request-URI标识的资源。响应必须包括一个      允许包含所请求的有效方法列表的标头      资源。

我们没有可以响应的有效方法,因为我们现在不希望在此资源上执行任何方法,因此我们无法返回405.

  

409 Conflict

     

最有可能发生冲突以响应PUT请求。对于      例如,如果正在使用版本控制并且该实体是PUT      包括对资源的更改与资产的更改      早期(第三方)请求,服务器可能会使用409响应      表示无法完成请求。在这种情况下,      响应实体可能包含差异列表      两种版本之间采用响应定义的格式      内容类型。

但是假设URI上已经存在资源(如何与任何东西发生冲突?)。

  

410 Gone

     

请求的资源在服务器上不再可用,没有      转发地址是已知的。预计这种情况会发生      被视为永久性具有链接编辑功能的客户端应该      用户批准后删除对Request-URI的引用。如果      服务器不知道,或无法确定,无论是否      条件是永久的,状态代码404(未找到)应该是      用来代替。

这个也很有意义。


我已经编辑了这篇文章几次,当它声称“使用410或404”时它被接受,但现在我认为403也可能适用,因为RFC没有声明403必须是权限相关(但它似乎是由流行的Web服务器实现的)。我想我已经淘汰了所有其他400代码,但随意评论(在你投票之前)。

答案 1 :(得分:0)

你的问题有一个未说明的,假定的前提,必须存在资源才能使PUT成功。这不是一个有效的假设。

规范的相关部分(RFC2616)说:

  

用户代理知道预期的URI,服务器不得尝试将请求应用于其他资源。

规范没有说,"引用URI的对象必须已经存在,以便PUT成为该URI的成功。"


简单的例子是通过REST实现的Web商店。 GET返回给定路径上对象的表示,而DELETE删除给定路径上的项目。这很容易。但POST和PUT并不难理解。 POST可以执行任何操作,但是POST的一次使用会在客户端指定的容器中创建一个对象,并让服务器返回该容器中新创建的对象的URI。 PUT更为有限;它为服务器提供给定URI处对象的表示。该对象可能已经存在,或者可能不存在。 PUT不是REPLACE的同义词。

在我看来,对于PUT来说409或410是错误的,除非容器本身 - 你试图放入的东西,不存在。

因此:

POST /container
   ==> returns 200 with `Location:/container/resource-12345`

PUT /container/resource-98928
   ==> returns 201 CREATED or 200 OK

PUT /this-container-does-not-exist/resource-22828282
   --> returns 400

当然,无论您是否希望您的服务器允许这些PUT语义,都取决于您。但是规范中没有任何内容表明您不得允许客户端提供他正在进行PUT的资源的URI。