如何以幂等的方式重命名资源?

6
我实现了一个API,可以将公司更名为以下内容:
PUT /companies/A
{
  "name": "B"
}

将会返回 HTTP 301 状态码,同时带有 Location 头指向公司的新 URI:/companies/B

如何使此操作具有幂等性,无论是否使用 If-Match 请求头?

  1. 不使用 If-Match 请求头:如果用户试图重命名一个不存在的公司,则服务器应该返回 HTTP 404 状态码。但这样做会导致合法的重命名操作不具有幂等性(第一次返回 301,之后返回 404)。这是有问题的,因为我希望客户端能够区分重命名失败(公司不存在)和已经重命名过的情况。

  2. 使用 If-Match 请求头:如果公司的 ETag 值依赖于公司名称,则后续的重命名操作将失败,因为前提条件不再成立。同样,这会让操作看起来像是失败了,而实际上已经执行成功。

3个回答

7

好的,这篇文章已经两年了,但我会回答它以防有人和我一样偶然碰到。

简短的回答是,在HTTP的角度来看,重命名(移动)资源是非幂等的,所以你应该使用POST而不是PUT

长话短说:PUT是一个“创建或替换”操作,由RFC 2616定义如下(强调我的):

PUT方法要求将封装的实体存储在提供的请求URI下。

RFC 7231(在提问时只存在于草案中),更清楚地表述了这一点:

PUT方法请求创建或用请求消息有效负载中的表示定义的状态替换目标资源的状态。成功地将给定表示放置后,对该目标资源进行的随后GET将导致在200OK)响应中发送等效表示。

因为成功地重命名将导致资源在一个不同的位置可用,所以PUT不适用。

PS. 可能你可以通过在请求体中包含公司的某种唯一标识符(而不考虑其名称或其他属性),来使PUT方式起作用,并允许您检测以前的重命名并发出相应的重定向。尽管如此,我认为这违反了协议,使用POST会更合适。


最终我决定将 GET /companies/{name} 重定向到 /companies/{id},并且只允许在后者上进行 PUT 操作。这样,GETPUT 都是幂等的。 - Gili
当使用PUT进行重命名时,我不明白为什么资源的新路径不能在位置标头中返回? - Alkanshel

2
PUT操作成功后应返回200或201。对于同一资源的后续请求,应返回301,并指示新资源的URI的适当响应正文。
404仅适用于真正找不到的资源,例如不存在并且从未存在的公司。
协议中所述,幂等性并不意味着调用始终返回相同的内容。它意味着没有副作用。此外,幂等性不适用于错误条件,任何非2xx(如301)的状态都是错误条件。
我确实钦佩规范中正确处理问题的承诺,但是像所有事物一样,它是可以解释的。

0

我认为在这里使用3xx并不合适。PUT操作成功,因此应该返回2xx。301意味着资源不在请求者认为的位置。

通常,我对人们实际上想要MOVE时却不使用MOVE感到很有趣 :-)


1
抱歉,我只限制于核心的HTTP方法。没有WEBDAV :) - Gili

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