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

发布于 2025-01-07 17:02:43 字数 741 浏览 1 评论 0原文

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

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

  1. 客户端向服务器发布用户资源的订单。如果用户不存在,则返回404 Not Found。
  2. 订单格式和信息经过验证。如果无效,则返回 400 Bad Request。
  3. 订单已处理。如果订单成功,订单会返回201 Created。如果遇到意外错误,则会返回 500 服务器错误。

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

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

这似乎不适合 400 或 500。如果有的话,我可以将其视为如果没有更好的代码,则返回 400 - 根据业务规则,该请求无效。它只是看起来不准确。

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

I'm creating a RESTful API that will process a number of user interactions, including placing orders using stored credit cards.

In the case of a successful order, I'm returning a 200 OK, and in the case where the order request is malformed or invalid I'm returning a 400 Bad Request. But what should I return if there is a problem during the actual processing of the order?

  1. Client POSTS order to server for a user resource. If user does not exist, 404 Not Found is returned.
  2. Order format and information is validated. If not valid, 400 Bad Request is returned.
  3. Order is processed. If the order is successful, a 201 Created is returned for the order. If an unexpected error is encountered, a 500 Server Error is returned.

The last step is the problem - what do I return if the order doesn't complete for any other reason? Possible scenarios could include:

  • Product is sold out
  • User maximum order limit reached
  • Credit card transaction failure (insufficient funds, etc.)

This doesn't seem like it would be appropriate for either a 400 or 500. If anything I could see it as a 400 if there's no better code - the request was invalid according to the business rules. It just doesn't seem accurate.

Edit: Also found this existing discussion of the same topic. All of the answers there seem to point to using status codes for this type of violation, with some discussion between using 400, 409, or the 422 extension.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

笑,眼淚并存 2025-01-14 17:02:43

您应该使用 4xx 作为业务规则。如果订单未被接受,请勿返回 2xx。 HTTP 是一个应用程序协议,永远不要忘记这一点。如果您返回 2xx,则无论您在正文中发送的任何信息如何,客户都可以假设订单已被接受。


From [RESTful Web Services Cookbook][1]:

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

You should use 4xx for business rules. Don't return 2xx if the order was not accepted. HTTP is an application protocol, never forget that. If you return 2xx the client can assume the order was accepted, regardless of any information you send in the body.


From [RESTful Web Services Cookbook][1]:

One common mistake that some web services make is to return a status
code that reflects success (status codes from 200 to 206 and from 300
to 307) but include a message body that describes an error condition.
Doing this prevents HTTP-aware software from detecting errors. For
example, a cache will store it as successful response and serve it to
subsequent clients even when clients may be able to make a successful
request.

温柔戏命师 2025-01-14 17:02:43

如果客户端可以修改请求来解决错误,则应使用 4xx 来表示客户端错误。使用 5xx 表示客户端无法真正解决的服务器错误。

产品售完将是服务器错误。客户端无法以某种方式修改请求来解决错误。您可以切换到其他产品,但这不是一个新的请求吗?

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

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

You should use 4xx for a client error if the client can modify the request to get around the error. Use a 5xx for a server error that the client can't really work around.

Product sold out would be a server error. The client can't modify the request in some fashion to get around the error. You could switch to another product but wouldn't that be a new request?

User maximum order limit reached is also a server error. Nothing the client can do to work around that error.

Credit card transaction failure would be a client error. The client could resubmit the request with a different payment method or credit card number to work around the error.

傾旎 2025-01-14 17:02:43

错误类型:

4×× Client Error

错误代码:

422 Unprocessable Entity

服务器了解请求实体的内容类型(因此 415 不支持的媒体类型状态代码是不合适的),并且请求实体的语法是正确的(因此 400 错误请求状态代码是不合适的),但是无法处理所包含的指令。

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

https://httpstatuses.com/422

Error type:

4×× Client Error

Error code:

422 Unprocessable Entity

The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

https://httpstatuses.com/422

苏佲洛 2025-01-14 17:02:43

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

我倾向于402 Payment required

根据Wikipedia :

保留供将来使用。最初的目的是该代码可能被用作某种形式的数字现金或小额支付方案的一部分,但这种情况并未发生,并且该代码通常不被使用。如果特定开发者超出了每日请求限制,Google Developers API 就会使用此状态。

事实上他们确实这样做

PAYMENT_REQUIRED (402)

  • 已达到开发者设定的每日预算限额。
  • 请求的操作需要的资源超过配额允许的资源。需要付款才能完成操作。
  • 所请求的操作需要经过身份验证的用户进行某种付款。

I know this question is old, but I came up with the very same question today. If my user runs out of credits, what status code should my REST API return?

I tend to lean towards 402 Payment Required:

According to Wikipedia:

Reserved for future use. The original intention was that this code might be used as part of some form of digital cash or micropayment scheme, but that has not happened, and this code is not usually used. Google Developers API uses this status if a particular developer has exceeded the daily limit on requests.

And indeed they do:

PAYMENT_REQUIRED (402)

  • A daily budget limit set by the developer has been reached.
  • The requested operation requires more resources than the quota allows. Payment is required to complete the operation.
  • The requested operation requires some kind of payment from the authenticated user.
ら栖息 2025-01-14 17:02:43

424 失败依赖怎么样?规范将其描述为:

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

但还有这个定义

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

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

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


另一个选项可能是422 Unprocessable Entity

服务器了解请求实体的内容类型(因此 415 不支持的媒体类型状态代码是不合适的),并且请求实体的语法是正确的(因此 400 错误请求状态代码是不合适的),但无法处理包含的指令。

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

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

MozDev 这表明客户端出现错误,具体来说:客户端不应在未经修改的情况下重复此请求。

Loopback 4 当输入验证失败时使用 422。


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

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

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

How about 424 Failed Dependency? The spec describes it as:

The method could not be performed on the resource because the requested action depended on another action and that action failed.

But there is also this definition:

Status code 424 is defined in the WebDAV standard and is for a case where the client needs to change what it is doing - the server isn't experiencing any problem here.

You can tell the client (or pretend) that you have internal actions which are supposed to create the order, and deduct the balance, and that one of those actions failed, albeit for perfectly valid reasons, and that's why the request failed.

As far as I can see, "action" is quite a broad term, and can be used in a variety of situations, including insufficient stock, insufficient credit, or warehouse party night.


Another option might be 422 Unprocessable Entity:

The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

For example, this error condition may occur if an XML request body contains well-formed (i.e., syntactically correct), but semantically erroneous, XML instructions.

Trying to request an item which is out of stock, or when you have insufficient credit, might be considered a mistake at the semantic level.

MozDev says this indicates a mistake on the client side, specifically: The client should not repeat this request without modification.

Loopback 4 uses 422 when input validation fails.


Arguably, insufficient stock or warehouse party night could be considered temporary states, so the request could be retried again later. That situation can be indicated by 503 Service Unavailable

The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.

The server MAY send a Retry-After header field to suggest an appropriate amount of time for the client to wait before retrying the request.

爺獨霸怡葒院 2025-01-14 17:02:43

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

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

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

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

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

I do'nt think 400 can be used for all the business scenario. It can be used for basic data input validation. Beyond that we might have hard to time fit other business logic into this error code. The error handled by this are mostly design time errors which developer will encounter possibly during the coding of the client.

Let's say all parameters are correct and let's say we are passing user account number into the request.

So request is now no longer a bad request, the server is able to accept the request. But now it is refusing to fulling the request based on new information available which is - account does not have sufficient balance.

I would suggest we should use 403 with appropriate error message in those scenarios.

Other possible error code could be 409 conflict. But that is used in scenarios where the resource is in in consistent state.

冷情妓 2025-01-14 17:02:43

我选择 406 不可接受

这是 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

I go with 406 Not Acceptable.

Here's a 4xx list:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文