REST-API,无效 DELETE 的正确 HTTP 状态代码

Posted

技术标签:

【中文标题】REST-API,无效 DELETE 的正确 HTTP 状态代码【英文标题】:REST-API, proper HTTP status code for invalid DELETE 【发布时间】:2014-06-22 14:41:07 【问题描述】:

我正在设计一个 RESTful API,它使用 HTTP 状态代码和动词作为通信的关键组件。

在宗教层面上,它是 RESTafarian 的***者。

决定 HTTP 状态代码的经验法则是 this graph 或类似资源。

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 个错误请求,反正没人在乎”,我没有需要快速修复或务实破解的问题。谢谢)

【问题讨论】:

【参考方案1】:

我不喜欢 404 表示无法找到资源的删除失败(或用于放置或补丁)的想法。 DNS 问题和人们遇到基于参数的路由问题是相当普遍的,如果无法找到实际站点,这些问题都会产生 404。引入这种类型的歧义会使诊断简单问题变得非常困难且不必要。对于 API,我认为 410 Gone 是表示未找到资源的更好选择

【讨论】:

"Gone"('目标资源在源服务器上不再可用')比“Not Found”('服务器没有当资源未找到且根本不知道存在时找到任何与Request-URI')匹配的东西?此外,“如果服务器知道 (...) 旧资源 永久不可用,则应使用 410 (Gone) 状态代码。” RFC 7231 和常识都告诉我们,Gone 表明我们确信某事在过去存在。您提出的建议不仅根据 RFC 7231 无效,而且 IMVHO 简直荒谬。【参考方案2】:

无效删除调用的响应代码取决于失败的原因。在你的情况下,我会选择:

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 是“您已登录,但您无权做您想做的事”。在您使用这些代码时,我没有发现任何异常情况。

说了这么多,我觉得我在某种程度上误解了这个问题。

【讨论】:

【参考方案3】:

通用指针:如果资源存在但用户无权对其执行操作,则应返回 401 而不是 403:

401 未经授权

类似于 403 Forbidden,但专门用于 当需要身份验证并且已失败或尚未验证时 提供。

403 禁止

请求是一个有效的请求,但服务器拒绝响应它。与 401 Unauthorized 响应不同,身份验证不会产生任何影响。

另见Correct HTTP status code when resource is available but not accessible because of permissions


如果现有资源不是你的,我会选择 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。

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

希望对你有所帮助。

【讨论】:

一个很好的观点,但我必须不同意,处理 401 和 403。正如您链接到的答案所指出的那样,在野外,401 通常提示输入用户名/密码,而 403 表示权限被拒绝。我正在使用 Oauth2 令牌进行访问,并且 401 会告诉客户端终止令牌并注销(例如,以防它过期或密码更改)。所以我以同样的方式解释了这一点,因此我不得不不同意你提出的实施方案。 很公平,但它也说 403 is for a page where authenticating won't change anything. 在您的情况下进行身份验证会有所作为,所以我认为您不应该使用 403 那句话让我彻夜难眠,也参与了办公室的很多讨论。但这意味着即使您以超级用户身份登录,也不会发生任何变化。所以我来解释它403 - is for page where the same authentication won't change anything,就我而言,成功登录并获得一个新令牌,但使用相同的client_id/user/scope 也许你看错了那句话?它没有说..where the same authentication won't change anything,但它说403意味着任何身份验证都不会改变任何东西 确实没有这么说。正如我所指出的,我是这样解释的。正如您所链接的答案以及他指出的“在野外”,我认为这意味着事实上的标准,这是处理 HTTP 的常见事情,我并不是要与很多常见的实现作斗争。据我所知,401 通常告诉例如手机上的应用程序应该将用户重定向到登录页面。如果在应用空闲时资源更改了所有者,并且用户稍后尝试删除它,即使他/她的令牌对正常使用有效,也会导致用户被注销

以上是关于REST-API,无效 DELETE 的正确 HTTP 状态代码的主要内容,如果未能解决你的问题,请参考以下文章

`main' 中的错误:free():无效指针(尽管没有使用 free 或 delete)

android 点击无效验证

无效的 SQL语句;期待 'DELETE'、'INSERT'、'PROCEDURE'、'SELECT'、或 'UPDATE

无效的 SQL语句;期待 'DELETE'、'INSERT'、'PROCEDURE'、'SELECT'、或 'UPDATE

Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格)

无效的SQL语句;预期的DELETE,INSERT,PROCEDURE,SELECT或UPDATE?