首页 文章

HTTP PUT和DELETE的幂等性

提问于
浏览
8

所以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 - this will now return a 404

  • PUT / api / items / 6 - WHAT SHOULD HAPPEN HERE? 404? 409? something else?

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

2 回答

  • 11

    RFC 2616,第9.6节,PUT:POST和PUT请求之间的根本区别体现在Request-URI的不同含义上 . POST请求中的URI标识将处理所包含实体的资源 . 该资源可能是数据接受过程,某些其他协议的网关或接受注释的单独实体 . 相反,PUT请求中的URI标识请求附带的实体 - 用户代理知道URI的用途,并且服务器不得尝试将请求应用于其他资源 .

    和:

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

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

    • 400 Bad Request :由于语法格式错误,服务器无法理解请求 .

    • 401 Unauthorized :请求需要用户身份验证 .

    • 402 Payment Required :此代码保留供将来使用 .

    • 406 Not Acceptable :根据请求中发送的接受标头,请求[...]标识的资源不可接受 .

    • 407 Proxy Authentication Required :此代码[...]表示客户端必须首先使用代理进行身份验证 .

    • 408 Request Timeout :客户端在服务器准备等待的时间内未生成请求 .

    • 411 Length Required :服务器拒绝接受没有定义Content-Length的请求 .

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

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

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

    404 Not Found服务器未找到与Request-URI匹配的任何内容 . 没有说明该病症是暂时的还是永久性的 . 如果服务器通过一些内部可配置的机制知道旧资源永久不可用且没有转发地址,则应该使用410(Gone)状态代码 . 当服务器不希望确切地说明请求被拒绝的原因,或者没有其他响应适用时,通常会使用此状态代码 .

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

    405不允许的方法Request-URI标识的资源不允许使用Request-Line中指定的方法 . 响应必须包含一个Allow标头,其中包含所请求资源的有效方法列表 .

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

    409冲突冲突最有可能发生在响应PUT请求时 . 例如,如果正在使用版本控制并且包含PUT的实体更改为与早期(第三方)请求所产生的资源冲突的资源,则服务器可能会使用409响应来指示它无法完成请求 . 在这种情况下,响应实体可能包含由响应Content-Type定义的格式的两个版本之间的差异列表 .

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

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

    这一点也很有道理 .


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

  • 0

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

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

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

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


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

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

    因此:

    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语义,都取决于您 . 但是规范中没有任何内容表明你不能允许客户端提供他正在PUTting的资源的URI .

相关问题