HTTP 状态代码 4xx 与 5xx
HTTP status code 4xx vs 5xx
我正在创建一个 REST API 并且发现在某些情况下很难为 return 选择正确的 HTTP 状态代码。
假设我期望某个值,当它不存在时我无法执行某个任务并且 return 出现错误。由于缺少值,服务器无法处理请求,但它是客户端发送的,格式正确但不完整,in. Would it be best to return a 4xx
or a 5xx
错误?
您想向客户发送什么样的回复完全取决于您。
但是在发送响应时,您必须意识到它应该是通用的并且清楚地说明导致请求失败的事件。
设计API就像设计客户端和服务器之间的协议。
服务器必须为客户端提供服务,直到遵循该协议或 API 规范。它应该在 Api 规范文档中明确指出。
在您的上述情况下,由于服务器正在接受带有请求参数的某些值,而客户端没有发送它,这是客户端的错误,因为客户端不同意在发送请求之前提供的 api 规范。
在这种情况下,服务器应该 return
HttpResponseStatus.BAD_REQUEST 在代码中等于 400。
提示:
我建议您不仅应该 return 错误代码,而且如果发生任何错误,还应在响应中提供一些错误消息。
例如
response : { errorCode:4xx, errorMessage:"Some thing went wrong"}
坚持标准!
向客户端发送哪个 HTTP 状态代码由您决定,但您确实应该遵守标准。 RFC 7231 是 HTTP/1.1 协议内容和语义的当前参考。在 HTTP 协议之上创建 API 时必读。
4xx
vs 5xx
状态码
对客户端错误使用 4xx
状态代码,对服务器错误使用 5xx
状态代码:
The 4xx
(Client Error) class of status code indicates that the client
seems to have erred. Except when responding to a HEAD
request, the
server SHOULD send a representation containing an explanation of the
error situation, and whether it is a temporary or permanent
condition. These status codes are applicable to any request method.
User agents SHOULD display any included representation to the user.
The 5xx
(Server Error) class of status code indicates that the server
is aware that it has erred or is incapable of performing the
requested method. Except when responding to a HEAD
request, the
server SHOULD send a representation containing an explanation of the
error situation, and whether it is a temporary or permanent
condition. A user agent SHOULD display any included representation
to the user. These response codes are applicable to any request
method.
您应该使用哪个状态码
对于您在问题中提到的情况,您可以使用 400
或者 422
(来自 WebDAV,一个 HTTP 扩展):
The 400
(Bad Request) status code indicates that the server cannot or
will not process the request due to something that is perceived to be
a client error (e.g., malformed request syntax, invalid request
message framing, or deceptive request routing).
11.2. 422 Unprocessable Entity
The 422
(Unprocessable Entity) status code means 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.
连同状态代码,请确保您发送的表示形式(例如 JSON 或 XML)包含对响应负载中错误情况的解释。看看 RFC 7807,它描述了 HTTP APIs 问题细节的标准。
很棒的决策图表
有关更多详细信息,请查看来自 Racksburg 的 decision chart:
状态代码大致分为三类:
从这里开始:
选择 2xx
和 3xx
状态代码:
正在选择 4xx
状态代码:
正在选择 5xx
状态代码:
TL;DR ,但在某些情况下可以放宽。
我认为 4xx 与 5xx 取决于服务器与客户端的关系。如果您正在构建 public API 或者您不确定 API 将如何使用,我同意接受的答案。事实上,我认为它应该是构建 APIs 时的默认选择。
但是,区分 4xx 和 5xx(具体为 400 和 500)会产生一定的成本。在某些情况下,成本可能不合理。假设您正在构建一个 API 并且您可以完全控制客户端。 API和client属于同一个app,会一起发布(Bounded Context in DDD lingo). Client and API are essentially a single app with HTTP used as a glue. Basically we are not using the API to be decoupled from the client. This often happens when building something like Backend For Frontend。在分层方面你可能有:
- 前端(了解业务规则)
- API/BFF(?)
- 领域模型或下游服务(执行业务
规则)
现在,在这种情况下构建 API 时,您可能想走捷径,只需将前端请求传递到下游,进行最少的翻译。基本上保持 API 层薄。该模型无论如何都会执行业务规则(例如通过抛出异常)。 Web 框架会自动将这些类型的崩溃转换为 500 错误。最终结果是您可能不会向客户端 return 'proper' 400 或 412 状态代码,而是 return 500,从 HTTP 的角度来看这是不正确的。但猜猜怎么了。您的客户不关心也不区分 400 和 500 - 它对它们一视同仁。两者都被认为是 'the app' 中的错误。客户端可能会对503s进行特殊处理,但我认为这是一个单独的考虑。
// internal api with a tightly coupled consumer (think SPA)
public Response BuyLifeInsurance(Request request) {
// how much upstream and downstream logic do you want to
// duplicate here knowing that _downstream still enforces
// all the rules and will throw on violation? And client
// also knows about the rules and the violation means a bug.
// Why think about 400 vs 412 semantics? Who cares if it
// is 400 or 500 if both are treated as bugs that should be
// fixed by _your_ team (either on client or server)? You
// should care about life insurance and not http purity anyway :)
// why not let the call below crash and return 500 and figure
// out where the bug is based on logs?
_downstream.BuyLifeInurance(
new Age(request.age),
new Amount(request.amount));
}
基本上在某些情况下,复制已经在客户端上实现并在下游模型中强制执行的业务逻辑可能会造成浪费。因此 API 层也可能以牺牲理论纯度为代价保持薄。我将这种情况称为弱 API™。一个有用的实验——如果不是 HTTP,你会在多大程度上关注与协议习惯用法的兼容?如果这不是 API 而是一个简单的内部库怎么办?恕我直言,它只有在您使用 API 与客户端分离时才值得(这是大多数情况,但也有我上面概述的例外情况)。
我发现通过添加 error: error.detail 了解错误详细信息将 return 一个有助于指导我发送什么错误代码的响应。在下面的代码中,响应(使用 Postman)指出了客户或用户的错误请求。这使错误代码 400 变得合适。
请注意,输入任何状态代码(例如 500)都不会产生任何影响,因为这只是一个假设。然而,错误详细信息将为您指明正确的方法。
如果(错误){
return res.status(400).send({
type: error.name,
status: "Failure",
error: error.detail,
message: "Please check the error message and try again!"
});
}
我正在创建一个 REST API 并且发现在某些情况下很难为 return 选择正确的 HTTP 状态代码。
假设我期望某个值,当它不存在时我无法执行某个任务并且 return 出现错误。由于缺少值,服务器无法处理请求,但它是客户端发送的,格式正确但不完整,in. Would it be best to return a 4xx
or a 5xx
错误?
您想向客户发送什么样的回复完全取决于您。
但是在发送响应时,您必须意识到它应该是通用的并且清楚地说明导致请求失败的事件。
设计API就像设计客户端和服务器之间的协议。 服务器必须为客户端提供服务,直到遵循该协议或 API 规范。它应该在 Api 规范文档中明确指出。
在您的上述情况下,由于服务器正在接受带有请求参数的某些值,而客户端没有发送它,这是客户端的错误,因为客户端不同意在发送请求之前提供的 api 规范。
在这种情况下,服务器应该 return HttpResponseStatus.BAD_REQUEST 在代码中等于 400。
提示: 我建议您不仅应该 return 错误代码,而且如果发生任何错误,还应在响应中提供一些错误消息。
例如
response : { errorCode:4xx, errorMessage:"Some thing went wrong"}
坚持标准!
向客户端发送哪个 HTTP 状态代码由您决定,但您确实应该遵守标准。 RFC 7231 是 HTTP/1.1 协议内容和语义的当前参考。在 HTTP 协议之上创建 API 时必读。
4xx
vs 5xx
状态码
对客户端错误使用 4xx
状态代码,对服务器错误使用 5xx
状态代码:
The
4xx
(Client Error) class of status code indicates that the client seems to have erred. Except when responding to aHEAD
request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents SHOULD display any included representation to the user.
The
5xx
(Server Error) class of status code indicates that the server is aware that it has erred or is incapable of performing the requested method. Except when responding to aHEAD
request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition. A user agent SHOULD display any included representation to the user. These response codes are applicable to any request method.
您应该使用哪个状态码
对于您在问题中提到的情况,您可以使用 400
或者 422
(来自 WebDAV,一个 HTTP 扩展):
The
400
(Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
11.2. 422 Unprocessable Entity
The
422
(Unprocessable Entity) status code means the server understands the content type of the request entity (hence a415
(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a400
(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.
连同状态代码,请确保您发送的表示形式(例如 JSON 或 XML)包含对响应负载中错误情况的解释。看看 RFC 7807,它描述了 HTTP APIs 问题细节的标准。
很棒的决策图表
有关更多详细信息,请查看来自 Racksburg 的 decision chart:
状态代码大致分为三类:
从这里开始:
选择 2xx
和 3xx
状态代码:
正在选择 4xx
状态代码:
正在选择 5xx
状态代码:
TL;DR
我认为 4xx 与 5xx 取决于服务器与客户端的关系。如果您正在构建 public API 或者您不确定 API 将如何使用,我同意接受的答案。事实上,我认为它应该是构建 APIs 时的默认选择。
但是,区分 4xx 和 5xx(具体为 400 和 500)会产生一定的成本。在某些情况下,成本可能不合理。假设您正在构建一个 API 并且您可以完全控制客户端。 API和client属于同一个app,会一起发布(Bounded Context in DDD lingo). Client and API are essentially a single app with HTTP used as a glue. Basically we are not using the API to be decoupled from the client. This often happens when building something like Backend For Frontend。在分层方面你可能有:
- 前端(了解业务规则)
- API/BFF(?)
- 领域模型或下游服务(执行业务 规则)
现在,在这种情况下构建 API 时,您可能想走捷径,只需将前端请求传递到下游,进行最少的翻译。基本上保持 API 层薄。该模型无论如何都会执行业务规则(例如通过抛出异常)。 Web 框架会自动将这些类型的崩溃转换为 500 错误。最终结果是您可能不会向客户端 return 'proper' 400 或 412 状态代码,而是 return 500,从 HTTP 的角度来看这是不正确的。但猜猜怎么了。您的客户不关心也不区分 400 和 500 - 它对它们一视同仁。两者都被认为是 'the app' 中的错误。客户端可能会对503s进行特殊处理,但我认为这是一个单独的考虑。
// internal api with a tightly coupled consumer (think SPA)
public Response BuyLifeInsurance(Request request) {
// how much upstream and downstream logic do you want to
// duplicate here knowing that _downstream still enforces
// all the rules and will throw on violation? And client
// also knows about the rules and the violation means a bug.
// Why think about 400 vs 412 semantics? Who cares if it
// is 400 or 500 if both are treated as bugs that should be
// fixed by _your_ team (either on client or server)? You
// should care about life insurance and not http purity anyway :)
// why not let the call below crash and return 500 and figure
// out where the bug is based on logs?
_downstream.BuyLifeInurance(
new Age(request.age),
new Amount(request.amount));
}
基本上在某些情况下,复制已经在客户端上实现并在下游模型中强制执行的业务逻辑可能会造成浪费。因此 API 层也可能以牺牲理论纯度为代价保持薄。我将这种情况称为弱 API™。一个有用的实验——如果不是 HTTP,你会在多大程度上关注与协议习惯用法的兼容?如果这不是 API 而是一个简单的内部库怎么办?恕我直言,它只有在您使用 API 与客户端分离时才值得(这是大多数情况,但也有我上面概述的例外情况)。
我发现通过添加 error: error.detail 了解错误详细信息将 return 一个有助于指导我发送什么错误代码的响应。在下面的代码中,响应(使用 Postman)指出了客户或用户的错误请求。这使错误代码 400 变得合适。
请注意,输入任何状态代码(例如 500)都不会产生任何影响,因为这只是一个假设。然而,错误详细信息将为您指明正确的方法。
如果(错误){
return res.status(400).send({
type: error.name,
status: "Failure",
error: error.detail,
message: "Please check the error message and try again!"
});
}