HTTP 响应码
HTTP 定义了一组标准的请求响应码,它们大致分为以下几类
- 1xx: 与旧版 HTTP 兼容,通常无需关心
- 2xx: 成功
- 3xx: 重定向(资源位于另一个位置,或自上次请求以来未更改)
- 4xx: 客户端错误(客户端做错了什么)
- 5xx: 服务器错误(服务器以非预期的方式失败)
2xx 成功码
- 响应状态码必须是201 已创建
- 必须返回一个 Location 头,其中包含已创建资源的 URI
- 应该在主体中返回资源的表示
- 异步资源创建
- 响应状态码必须是202 已接受
- 必须返回一个 Location 头,设置为以下其中之一
- 如果已知,资源的 URI 将被创建。
- 客户端可用于查询异步操作进度的状态资源的 URI。
- 同步资源删除
- 对于所有其他成功的请求,返回码应该是 200 OK。
- 如果请求尝试将资源置于其已经处于的状态(例如,锁定已经锁定的实例),则返回码应在 2xx 成功 范围内(通常与如果状态已更改时给出的返回码匹配)。当资源的结果状态与用户请求的状态相同时,不宜使用 409 冲突。
5xx 服务器错误码
这些代码表示服务器或网关遇到错误或无法执行请求的方法。它们指示客户端请求导致服务器端错误,而不是客户端错误。
它们应该用于指示在请求过程中发生的错误,这些错误不能仅由客户端单独解决。5xx 系列中每个代码的含义都有其具体含义,在部署之前应充分研究。
服务器 不应 将服务器端堆栈跟踪/回溯输出返回给最终用户。堆栈跟踪和回溯属于服务器端日志,不应通过 HTTP API 返回给最终用户。
失败码说明
- 如果请求导致 OpenStack 用户超出其配额,则返回码应为 403 Forbidden。不要使用 413 Request Entity Too Large。
- 对于格式错误的请求,返回码应为 400 Bad Request。不要使用 422 Unprocessable Entity。
- 如果 API 限制了集合属性的长度,并且请求超过了长度限制,则返回码应为 400 Bad Request。客户端应调整请求以获得成功,并且不应期望重复请求会成功。在这种情况下,不要使用 403 Forbidden,因为这与超出配额不同——当超出配额时,服务器环境必须发生变化才能使后续请求成功。
- 如果请求包含主体中对不存在资源的引用(不是 URI),则代码应为 400 Bad Request。不要使用 404 NotFound,因为 RFC 7231(第 6.5.4 节)提到 原始服务器未为目标资源找到当前表示 用于 404,并且 目标资源的表示 意味着 URI。一个很好的例子是当请求将服务器调整为不存在的 flavor 时。服务器是 URI 中的资源,只要它存在,404 就永远不会是正确的响应。422 Unprocessable Entity 也是这种情况下的一个选项,但不要使用 422,因为它未在 RFC 7231 中定义,并且不是标准。由于 400 响应码可以表示很多内容,因此返回的错误消息必须清楚地表明主体中引用的资源不存在,以便使用者清楚地了解需要做什么才能更正问题。
- 如果请求主体包含意外属性,服务器应返回 400 Bad Request 响应。不要通过忽略错误的属性来像往常一样处理请求。返回错误允许客户端知道哪个属性错误并有可能修复错误的请求或错误的编码。(例如,additionalProperties 应该在 JSON-Schema 定义中为 false)
- 同样,如果 API 支持查询参数,并且请求包含未知或不受支持的参数,服务器应返回 400 Bad Request 响应。不应默默忽略请求 URL 中的无效值,因为响应可能与客户端的期望不符。例如,考虑 API 允许通过在查询字符串中指定“?name=foo”来按名称进行筛选的情况,并且在其中一个请求中存在拼写错误,例如“?nmae=foo”。如果此错误被默默忽略,用户将获得所有资源而不是仅命名为“foo”的资源,这将是不正确的。返回的错误消息应清楚地表明问题,以便用户可以更正并重新提交。
- 如果对已知资源 URI 发出请求,但用于该请求的 HTTP 方法不受该资源支持,则返回码应为 405 Method Not Allowed。响应应包含 Allow 头,其中包含资源接受的请求方法列表。
- 如果发出请求以尝试对已经正在执行该操作的资源执行操作,因此无法满足请求(例如,对已经处于快照过程中的实例进行快照),则返回码应为 409 Conflict。
- 不应将 500 Internal Server Error 返回给用户,因为用户错误导致失败,可以通过更改客户端请求来修复。应为任何无法由客户端修复的错误状态而返回 500 错误,并且需要服务操作员执行某些操作才能修复。也可能由于检测到但无法恢复的错误(例如,由于与另一个服务组件通信失败而导致的 MessageQueueTimeout、由于磁盘已满而导致的 IOError 或类似错误)而故意引发此错误。
注意
如果返回了错误响应主体,则它必须符合 错误 指南。
常见错误
在 OpenStack 中 RESTful API 的实现中已经出现了很多常见错误。本节试图列举它们,并说明它们为什么是错误的,并提出未来的替代方案。
使用 501 - Not Implemented
在 Folsom 时代,一些项目开始使用 501 表示“功能未实现” - openstack-dev 上的讨论
这是对 HTTP 的完全错误的解读。“方法”在 HTTP 中意味着非常具体的东西,它意味着 HTTP 方法。GET / HEAD / POST / PUT / PATCH / OPTIONS / TRACE 中的一种。
501 错误的目的是告诉客户端 POST 现在并且永远不会是调用服务器上任何资源的适当方法。适当的客户端操作是禁止 POST 并确保没有代码尝试使用它。这源于 HTTP 的早期,当时有数百种商业 HTTP 服务器实现,并且供应商无法就所有 HTTP 方法都将由服务器处理达成一致。RFC RFC 7231(第 6.6.2 节)对此进行了澄清。
如果假设以下 rfc 语句为真:“当服务器不识别请求方法并且无法为任何资源支持它时,这是适当的响应。”这与更狭义的解读不相容,因为我们已经说过所有客户端都正确地实现了“永远不要再向任何资源发送另一个 POST 请求”。这就像说商业场所的“关闭”标志意味着既今天关闭,也永久关闭,并且可以由城市明天拆除建筑物。声明两者都是有效的解读只会造成眼泪和困惑。
我们生活在一个非常不同的世界中,这个世界由 Apache 和 Nginx 主导。因此,501 是您不太可能在野外看到的。但这并不意味着我们可以用我们自己的定义来代替它。
今后,项目应使用 400“BadRequest”响应来表示这种情况,并向用户返回更具体的错误消息,说明该功能未在该云中实现。在某些情况下,404“NotFound”也可能适用。但是,我们返回“功能未实现”的最常见的地方是当我们向形式为 /resource/{id}/action 的 URI 发布操作时。显然找到了该 URI,但是一些操作不受支持。返回 404(默认情况下可缓存)会使客户端认为 /resource/{id}/action 根本不存在于服务器上。