REST-API,无效DELETE的正确HTTP状态码是什么?

22
我正在设计一个RESTful API,使用HTTP状态码和动词作为通信的关键组件。
在宗教层面上,它是RESTafarian的狂热支持者。
决定HTTP状态码的经验法则是这个图表或类似资源。
  • GET /api/documents/1 - 401 用户未登录
  • GET /api/documents/1 - 200 用户有权限
  • GET /api/documents/1 - 403 用户没有权限
  • DELETE /api/documents/1 - 204 用户有权限
  • DELETE /api/documents/1 - 403 用户没有权限
  • GET /api/documents/2 - 404 用户权限无关紧要,资源不存在
  • DELETE /api/documents/2 - 404 用户权限无关紧要,资源不存在
  • DELETE /api/documents/1 - 404 用户有权限,资源已被删除
  • DELETE /api/documents/1 - 404 用户没有权限,资源已被删除

目标:

  • 使用中保持一致性
  • 不要通过错误泄露私人信息
  • 适当地使用客户端或中间层缓存的状态码
  • 尽早失败,将查找最小化

在这种情况下,有很多不同的状态码可供选择(404、403、410、405),在我的情况下,如果资源不属于您,则对现有资源使用403以不清除缓存,并对所有不存在的资源使用404,以告诉客户端清除该数据。

但我不喜欢在资源不属于您的情况下从403切换到404。

我很想听听其他人如何解决这个用例,或者总体上您认为适合发送所有无效的DELETE调用的状态码是什么,因为我认为这是最难简洁的之一。

(互联网上关于REST的许多讨论和答案都只是“抛出400错误请求,反正没有人在乎”,我没有需要快速修复或实用主义黑客的问题。谢谢)

3个回答

19

一般指针:如果存在资源但用户未被授权执行操作,则应返回401而不是403:

401 未经授权

类似于403禁止,但专门用于需要进行身份验证但已失败或尚未提供身份验证的情况。

403 禁止

请求是有效的,但服务器拒绝响应它。与401未经授权的响应不同,进行身份验证也没有任何影响。

另请参见权限限制时正确的HTTP状态码


如果不属于您,则在现有资源上选择403以不清除缓存,并在所有不存在的资源上选择404以告诉客户端擦除该数据。

如前所述,应使用401而不是403。如果您只想说“抱歉,找不到资源”,则可以返回404。但是,如果您想说“资源曾经在这里,但现在已不存在,永远不会再次存在”(这似乎是您的情况),则可以返回410:

410 消失

表示所请求的资源不再可用,并且将不再可用。当资源被有意删除并且应清除资源时,应使用此选项。收到410状态代码后,客户端不应在未来重新请求该资源。搜索引擎等客户端应从其索引中删除该资源


总之,在您的情况下,这是我实施它的方式。我所做的更改以粗体表示。

  • GET /api/documents/1 - 401 用户未登录
  • GET /api/documents/1 - 200 用户有权访问
  • GET /api/documents/1 - 401 用户没有权限访问
  • DELETE /api/documents/1 - 204 用户有权删除
  • DELETE /api/documents/1 - 403 用户没有权限删除
  • GET /api/documents/2 - 404 资源不存在,权限无关
  • DELETE /api/documents/2 - 404 资源不存在,权限无关
  • DELETE /api/documents/1 - 410 用户有权删除,资源已被删除
  • DELETE /api/documents/1 - 401 用户没有权限删除,资源已被删除

对于最后一个,如果你不想让未经授权的用户知道已经删除了资源,可以返回401。如果不在意,可以返回410。这取决于你。

我不喜欢在资源不属于你的情况下从403切换到404。

根据情况返回不同的状态码是完全可以的。

希望这对你有所帮助。


1
非常好的观点,但我必须反对处理401和403。正如您链接的答案所指出的那样,在实际应用中,401通常会提示输入用户名/密码,而403则表示权限被拒绝。我们正在使用Oauth2令牌进行访问,401将告诉客户端销毁令牌并注销(例如在令牌过期或更改密码的情况下)。因此,我以同样的方式解释了它,因此我不同意您提出的实现方案。 - Cleric
那个特定的句子让我彻夜难眠,也在办公室里进行了很多讨论。但这意味着即使您以超级用户身份登录,也不会有任何变化。因此,我已经将其解释为“403-用于页面,其中相同的身份验证不会改变任何内容”,在我的情况下,成功登录并获取新令牌,但使用相同的client_id / user / scope。 - Cleric
谢谢你的想法 :) - Cleric
@Cleric 如果你的问题已经解决了,你介意接受任何一个答案吗? - Tim
401状态码仅在请求期间身份验证失败时使用。因此,如果您已经通过身份验证但正在请求其他人的资源,则401状态码会产生误导性。例如,某些人可以实现客户端,使得401重定向到登录页面。然而,403(或隐藏在404后面)意味着您可以继续进行其他请求而无需重新授权。 - Guney Ozsan
显示剩余6条评论

5
无效删除调用的响应代码取决于失败原因。 对于您的情况,我建议如下操作: - 用户有权限 - DELETE /api/documents/1 - 204 No Content - 用户权限无关,资源不存在 - DELETE /api/documents/2 - 404 Not Found - 用户有权限,资源已经被删除 - DELETE /api/documents/1 - 410 Gone - 用户没有权限,并且资源已经被删除 - DELETE /api/documents/1 - 403 Forbidden
最后一个调用值得讨论。 我认为(并且您的图表也同意),用户缺少权限优先于资源已被删除。 如果用户获得了410,那么您将泄漏信息(资源已被删除)。
至于401/403,401是“您尚未登录”,403是“您已经登录,但没有执行所需操作的权限”。 您对这些代码的使用没有任何异常。
说了这么多,我觉得自己可能会误解问题。

1

我不喜欢将404表示为删除失败时资源无法找到的情况(或者对于put或patch也是如此)。DNS问题和基于参数的路由问题很常见,如果实际站点找不到,这两个问题都会产生404。引入这种模糊性可能会使诊断简单问题变得非常困难且没有必要。我认为使用410 Gone更好地表示API中未找到资源的情况


2
“Gone”('目标资源在源服务器上不再可用')与“Not Found”('服务器未找到与请求URI匹配的任何内容')相比,对于未找到且根本不存在的资源,“Gone”更好吗?此外,“410(Gone)”状态代码应该被使用,如果服务器知道(...)某个旧资源已经永久性不可用。RFC 7231和常识都表明,“Gone”表示我们确信过去曾经有东西存在。你提出的东西不仅在RFC 7231的光芒下是无效的,并且,在我看来也是荒谬的。 - user719662

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