我正在创建一个REST API,并且发现在某些情况下很难选择正确的HTTP状态代码。
我们假设我期望某个值,当它不存在时,我无法执行某个任务并返回错误。由于缺少值,服务器无法处理请求,但是发送它的客户端,状态良好但不完整。是否最好返回4xx
或5xx
错误?
答案 0 :(得分:19)
决定将您发送给客户端的HTTP状态代码取决于您,但您确实应该遵守标准。 RFC 7231是HTTP / 1.1协议的内容和语义的当前引用。在HTTP协议的顶部创建API时必须阅读。
4xx
vs 5xx
状态代码将4xx
状态代码用于客户端错误,并使用5xx
状态代码来解决服务器错误:
4xx
(客户端错误)类状态代码表示客户端 似乎有错误。除了回复HEAD
请求时, 服务器应该发送一个包含对的解释的表示 错误情况,无论是暂时的还是永久的 条件。这些状态代码适用于任何请求方法。 用户代理应该向用户显示任何包含的表示。
5xx
(服务器错误)类状态代码表示服务器 知道它有错误或无法执行 要求的方法。除了回复HEAD
请求时, 服务器应该发送一个包含对的解释的表示 错误情况,无论是暂时的还是永久的 条件。用户代理应该显示任何包含的表示 给用户。这些响应代码适用于任何请求 方法
对于您在问题中提到的情况,您可以使用400
或422
(来自WebDAV,HTTP扩展程序):
400
(错误请求)状态代码表示服务器不能或 由于被认为是某种东西,它不会处理请求 客户端错误(例如,格式错误的请求语法,无效请求 消息框架或欺骗性请求路由)。
11.2. 422 Unprocessable Entity
422
(不可处理的实体)状态代码表示服务器 了解请求实体的内容类型(因此a415
(不支持的媒体类型)状态代码不合适),以及 请求实体的语法是正确的(因此400
(错误请求) 状态代码不合适但是无法处理包含的内容 说明。例如,如果是XML,则可能会出现此错误情况 请求正文包含格式正确(即语法正确),但是 语义错误的XML指令。
与状态代码一起,确保发送包含响应有效负载中错误情况说明的表示(如JSON或XML)。查看RFC 7807,它描述了HTTP API问题详细信息的标准。
有关详情,请查看Racksburg的decision chart:
状态代码分为三大类:
从这里开始:
选择2xx
和3xx
状态代码:
选择4xx
状态代码:
选择5xx
状态代码:
答案 1 :(得分:2)
您想要发送给客户的回复完全取决于您。
但是在发送回复时,您必须意识到它应该是通用的,并且清楚导致请求失败的事件。
设计 API 就像设计客户端和服务器之间的协议一样。 在遵循该协议或API规范之前,服务器必须服务于客户端。它应该在Api规范文档中明确指出。
在上述情况下,由于服务器接受了请求参数的某些值而客户端没有发送它,因此客户端在发送请求之前未同意提供api规范,因此客户端出现故障。
在这种情况下,服务器应该返回 HttpResponseStatus.BAD_REQUEST ,在代码中等于 400 。
提示强> 我建议您不要只返回错误代码,但如果发生任何错误,还应该在响应中提供一些错误消息。
例如
response : { errorCode:4xx, errorMessage:"Some thing went wrong"}
答案 2 :(得分:0)
TL; DR Stick to standards!,但在某些情况下可以放宽。
我认为4xx与5xx取决于服务器与客户端的关系。如果您正在构建公共API,或者不确定如何使用该API,则我同意接受的答案。实际上,我认为在构建API时它应该是默认选择。
但是,区分4xx和5xx(具体为400和500)会产生一定的成本。在某些情况下,成本可能不合理。假设您正在构建API,并且可以完全控制客户端。 API和客户端都属于同一个应用程序,它们都将一起发布(在DDD语言中为Bounded Context)。客户端和API本质上是一个单独的应用程序,使用HTTP作为粘合剂。基本上,我们没有使用API与客户端分离。构建Backend For Frontend之类的东西时通常会发生这种情况。在分层方面,您可能需要满足以下条件:
现在,在这种情况下构建API时,您可能需要采取一种捷径,并且只需最少的转换即可向下游传递前端请求。基本上保持API层较薄。该模型无论如何都会强制执行业务规则(例如,引发异常)。 Web框架会将这些类型的崩溃自动转换为500错误。最终结果是您可能不会向客户端返回“正确的” 400或412状态代码,而是将返回500,这从HTTP角度来看是不正确的。但猜猜怎么了。您的客户不在乎,也不会在400和500之间进行区分-对待它们的方式相同。两者均被视为“应用程序”中的错误。客户端可能会对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与客户端分离的情况下才需要付费(这是大多数情况,但是我在上面概述了一些例外情况)。
答案 3 :(得分:0)
我发现通过添加 error:error.detail 了解错误的详细信息将返回响应,该指导有助于指导我发送什么错误代码。在下面的代码中,响应(使用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!"
});
}