【发布时间】:2020-03-11 05:49:52
【问题描述】:
这专注于后端 Web 应用程序开发。我更喜欢在我的应用程序中使用映射到我的业务逻辑的 HTTP 状态代码。例如,如果发出请求但未找到用户,我将抛出异常并使用@ControllerAdvice 或@ExceptionHandler 处理它并映射到未找到的 404。有时我在 try catch 块中有这些用于记录并重新抛出异常。我更喜欢这种方式,因为 API 的实现者可以只查看状态代码并继续前进,如果它是预期的客户端错误,则无需反序列化。一位同事认为,如果它是应用程序的预期状态,那么一切都应该是 200,其中包含失败原因的响应正文而不是预期的响应对象,因为执行 catch 块是一项昂贵的操作。我个人不喜欢这种方法,因为您的 API 的实现者必须检查响应实体并尝试将其反序列化为预期的对象,或者如果失败将其反序列化为某个已知的异常对象,因为它始终为 200。
TLDR:我的问题是我看到很多关于为什么执行 catch 块可能会很昂贵的文章,具体取决于堆栈跟踪,并且错误处理不应该是控制流的一部分,但我很难同意这一点,因为Spring 具有 @ControllerAdvice 、 @ExceptionHandler 或更新的 ResponseStatusException 等功能。我也不同意 HTTP 状态码指的是协议,而 200 只是意味着成功传输的说法。如果是这种情况,那么 401 和 403 应该是 200,因为响应处理得很好,客户端只是没有授权或正确的授权。这个论点对我说,一切都应该是 200,为什么还要使用其他状态码?我还处于职业生涯的早期,所以如果我遗漏了一些明显的东西,请原谅。
【问题讨论】:
-
执行 catch 块很便宜;唯一昂贵的是在新的异常对象上填充堆栈跟踪。你是对的,任何像
"error": true这样的 2xx 响应都违反了 HTTP 的明确合同;查看the long list of error codes 以演示预期通过 4xx 发出信号的类型。 -
假设在一个例子中,客户端通过 id 向用户发出请求,而服务器没有找到用户是 404 还是 200 响应体为空?对我来说这是 404 对我的同事来说是 200 tools.ietf.org/html/rfc7231#section-6.5.4
-
/users?id=1234返回[],因为集合资源是多值的。/users/1234返回 404。 -
这是有道理的。关于使用异常进行控制流,我仍然很难做出正确的反应。您提到了
the only thing that's costly is filling in stack traces on new exception objects,但这是应用程序流程的一部分,以便调用`@ControllerAdvice 等,因此它会定期发生。 -
在应用程序的 Java 部分(在 Web 边界内),使用按契约设计的原则:API 应该解释前置条件、预期输入、后置条件和返回值。例外就是正常规则的例外(比如用
IOException说“我不能这样做,因为网络出现故障”)。决定是使用null、Optional.empty()还是NotFoundException取决于在您的业务建模中什么是有意义的,并且不要让您的模型仅仅符合假设的性能标准。
标签: java spring spring-boot rest error-handling