对于一般不成功的请求(不是错误),适当的 HTTP 状态代码响应是啥?

Posted

技术标签:

【中文标题】对于一般不成功的请求(不是错误),适当的 HTTP 状态代码响应是啥?【英文标题】:What is the appropriate HTTP status code response for a general unsuccessful request (not an error)?对于一般不成功的请求(不是错误),适当的 HTTP 状态代码响应是什么? 【发布时间】:2012-03-11 23:56:00 【问题描述】:

我正在创建一个 RESTful API,它将处理许多用户交互,包括使用存储的信用卡下订单。

如果订单成功,我会返回 200 OK,如果订单请求格式错误或无效,我会返回 400 Bad Request。但是如果在实际处理订单的过程中出现问题,应该怎么退呢?

    客户端将订单发布到服务器以获取用户资源。如果用户不存在,则返回 404 Not Found。 订单格式和信息已验证。如果无效,则返回 400 Bad Request。 订单已处理。如果订单成功,则该订单返回 201 Created。如果遇到意外错误,则返回 500 服务器错误。

最后一步是问题 - 如果由于任何其他原因订单未完成,我应该返回什么?可能的情况包括:

产品已售罄 达到用户最大订单限制 信用卡交易失败(资金不足等)

这似乎不适用于 400 或 500。如果没有更好的代码,我可以将其视为 400 - 根据业务规则,请求无效。它似乎并不准确。

编辑:还发现了同一主题的this existing discussion。那里的所有答案似乎都指向对此类违规使用状态代码,并在使用 400、409 或 422 扩展名之间进行了一些讨论。

【问题讨论】:

我喜欢 '422 unprocessable entity' 验证错误。并将其用于上述示例,在响应中包含一条带有实际业务问题“产品已售罄”的消息,如果客户需要根据响应以编程方式做出不同的决定,则可能添加您自己的“代码” 在进入 422 之前,请考虑是否支持 WebDAV 功能 【参考方案1】:

您应该将 400 用于业务规则。如果订单未被接受,请勿返回 2xx。 HTTP 是一种应用程序协议,永远不要忘记这一点。如果您返回 2xx,客户可以假定订单已被接受,而不管您在正文中发送的任何信息。


来自RESTful Web Services Cookbook:

一些网络服务常犯的一个错误是返回一个状态 反映成功的代码(状态代码从 200 到 206 和从 300 到 307),但包括描述错误情况的消息正文。 这样做可以防止 HTTP 感知软件检测错误。为了 例如,缓存会将其存储为成功响应并将其提供给 后续客户即使客户可能能够成功 请求。

4xx 和 5xx 之间由您决定,但您应该使用错误状态代码。

【讨论】:

对于这种方法与其他方法相比,您有任何示例或参考吗?您和 Widor 的答案都是有道理的,一个是从 HTTP 作为应用程序协议的角度来看,另一个是因为它严格用于传输目的。规范将其定义为“应用程序级协议”,有点模糊。在研究这个问题时,我还看到了网络上的观点和例子。 这是真的。 你的意思是,'你应该使用 4xx 的业务规则'? 我假设我们正在讨论 RESTful HTTP 服务上下文中的 HTTP 状态代码。我读了几遍菲尔丁博士的论文。我对菲尔丁博士论文的一个解释是,REST 是一套帮助塑造/架构网络的指南。在网络上,我看不到业务规则错误返回 400。因此,我倾向于使用 200 的业务规则,HTTP 响应正文详细说明业务错误。现在这对于请求参数验证会有所不同,其中参数根据合同明显无效——即 400。【参考方案2】:

如果客户端可以修改请求以绕过错误,您应该为客户端错误使用 4xx。对客户端无法真正解决的服务器错误使用 5xx。

产品售罄将是服务器错误。客户端不能以某种方式修改请求来绕过错误。您可以切换到另一种产品,但这不是一个新的要求吗?

达到用户最大订单限制也是服务器错误。客户端无法解决该错误。

信用卡交易失败将是客户端错误。客户可以使用不同的付款方式或信用卡号重新提交请求以解决该错误。

【讨论】:

如果达到订单限制,客户不应该提醒用户并让他们适当地更改他们的请求吗?这似乎是一个 4xx 错误。售罄的产品也是如此。 5xx 错误适用于由系统以某种方式发生故障引起的错误,而不是业务规则不允许的操作。 我同意上面的评论。 5xx 错误用于服务器出现问题时。业务规则出现 4xx 错误。【参考方案3】:

错误类型:

4×× Client Error

错误代码:

422 Unprocessable Entity

服务器理解请求实体的内容类型(因此 415 Unsupported Media Type 状态码是不合适的),并且请求实体的语法是正确的(因此 400 Bad Request 状态码是不合适的)但无法处理包含的指令。

例如,如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会发生这种错误情况。

https://httpstatuses.com/422

【讨论】:

【参考方案4】:

我知道这个问题很老,但我今天提出了同样的问题。如果我的用户用完了积分,我的 REST API 应该返回什么状态代码?

我倾向于402 Payment Required

根据Wikipedia:

保留以供将来使用。最初的意图是这个代码可能会被用作某种形式的数字现金或小额支付计划的一部分,但这并没有发生,而且这个代码通常不被使用。如果特定开发人员超出了每日请求限制,Google Developers API 会使用此状态。

确实是they do:

PAYMENT_REQUIRED (402)

已达到开发者设置的每日预算限制。 请求的操作需要的资源超出配额允许的范围。需要付款才能完成操作。 请求的操作需要经过身份验证的用户支付某种费用。

【讨论】:

这是最深思熟虑和合乎逻辑的答案。【参考方案5】:

424 Failed Dependency 怎么样?规范将其描述为:

无法对资源执行该方法,因为请求的操作依赖于另一个操作并且该操作失败。

但也有this definition:

状态码 424 是在 WebDAV 标准中定义的,适用于客户端需要更改其正在执行的操作的情况 - 服务器在这里没有遇到任何问题。

您可以告诉客户(或假装)您有应该创建订单并扣除余额的内部操作,并且其中一个操作失败了,尽管出于完全正当的原因,这就是请求失败的原因.

据我所知,“行动”是一个相当宽泛的术语,可以用于多种情况,包括库存不足、信用不足或仓库派对之夜。


另一个选项可能是422 Unprocessable Entity:

服务器理解请求实体的内容类型(因此 415 Unsupported Media Type 状态码是不合适的),并且请求实体的语法是正确的(因此 400 Bad Request 状态码是不合适的)但无法处理包含的指令。

例如,如果 XML 请求正文包含格式正确(即语法正确)但语义错误的 XML 指令,则可能会发生这种错误情况。

尝试请求缺货或信用不足的商品可能会被视为语义级别的错误。

MozDev says 这表示客户端出错,具体是:客户端不应该不修改就重复这个请求。

当输入验证失败时回送 4 uses422。


可以说,库存不足或仓库派对之夜可以被视为临时状态,因此可以稍后重试请求。这种情况可以通过503 Service Unavailable来表示

由于临时过载或计划维护,服务器当前无法处理请求,延迟一段时间后可能会得到缓解。

服务器可以发送一个 Retry-After 头字段来建议客户端在重试请求之前等待的适当时间。

【讨论】:

这些都与付款无关。我将使用上一个答案中的 402!【参考方案6】:

我不认为 400 可以用于所有业务场景。它可用于基本的数据输入验证。除此之外,我们可能很难将其他业务逻辑融入此错误代码。由此处理的错误主要是开发人员在客户端编码期间可能会遇到的设计时错误。

假设所有参数都正确,假设我们将用户帐号传递到请求中。

所以请求现在不再是错误请求,服务器能够接受请求。但现在它拒绝根据可用的新信息完成请求 - 帐户没有足够的余额。

我建议我们应该在这些情况下使用带有适当错误消息的 403。

其他可能的错误代码可能是 409 冲突。但这用于资源处于一致状态的场景。

【讨论】:

【参考方案7】:

我选择 406 Not Acceptable

这是一个 4xx 列表:

const HTTP_BAD_REQUEST = 400;
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
const HTTP_FORBIDDEN = 403;
const HTTP_NOT_FOUND = 404;
const HTTP_METHOD_NOT_ALLOWED = 405;
const HTTP_NOT_ACCEPTABLE = 406;
const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
const HTTP_REQUEST_TIMEOUT = 408;
const HTTP_CONFLICT = 409;
const HTTP_GONE = 410;
const HTTP_LENGTH_REQUIRED = 411;
const HTTP_PRECONDITION_FAILED = 412;
const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
const HTTP_REQUEST_URI_TOO_LONG = 414;
const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;
const HTTP_I_AM_A_TEAPOT = 418;                                               // RFC2324
const HTTP_MISDIRECTED_REQUEST = 421;                                         // RFC7540
const HTTP_UNPROCESSABLE_ENTITY = 422;                                        // RFC4918
const HTTP_LOCKED = 423;                                                      // RFC4918
const HTTP_FAILED_DEPENDENCY = 424;                                           // RFC4918
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425;   // RFC2817
const HTTP_UPGRADE_REQUIRED = 426;                                            // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428;                                       // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429;                                           // RFC6585

【讨论】:

虽然状态代码 406 的名称本身可能听起来很准确,但您需要注意每个状态代码都有一个权威的文本描述。状态码 406 的描述不适合当前的情况。例如,请参阅httpstatuses.com/406。 @Zero3 是对的,此代码表示响应类型不可接受,因为客户端发送的 Accept Headers 与端点发送的 MediaType(s) 不匹配,例如application/json vs. text/plain

以上是关于对于一般不成功的请求(不是错误),适当的 HTTP 状态代码响应是啥?的主要内容,如果未能解决你的问题,请参考以下文章

HTTP | 常用状态码记录

对于未找到某些链接资源的 PUT 操作,HTTP 404 是不是是适当的响应? [关闭]

HTTP错误码

http请求状态码解析

HTTP的响应状态码

HTTP的状态码大全