【发布时间】:2021-08-10 21:30:44
【问题描述】:
我正在开发一个 Spring Boot 应用程序。 Spring 自动处理来自客户端的一些输入错误。例如,如果我有这样的控制器:
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping(value = "/{id}", produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Order> getOrder(
@PathVariable("id") int id) {
Order order = this.orderService.get(id);
if (order != null) {
return new ResponseEntity<>(order, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}
如果 id 输入未包含在来自客户端的请求中,或者 Spring 无法将其设为 int,则 Spring 将自动返回正确的 400 状态代码。
现在,假设我想记录此方法中由于业务逻辑错误而发生的任何故障。我创建了一个控制器建议:
@ControllerAdvice
public class ControllerExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerExceptionHandler.class);
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler({ RuntimeException.class })
public ResponseEntity<Object> handleError(final RuntimeException ex) {
LOGGER.error("Got internal server error.", ex);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
问题是现在如果客户端发送错误的输入,我的控制器建议方法正在运行并返回 500,而不是 400。如何创建一个忽略 Spring 抛出的异常的异常处理程序?
我不想具体说明我捕获的错误,因为我想捕获并记录任何内容。如果一个库抛出一个我什至不知道它会抛出的异常,我想记录它。如果我引入了一个潜在的 NullPointerException,我想记录它。但是,我想保留 Spring 对其异常的有用默认处理。
我可以在处理程序方法中重新抛出异常,如果它是 Spring 异常,Spring 会处理它。但后来我记录了错误的客户端输入,这是我不想要的。尤其是在显示“Got internal server error”的日志中,这是一种误导。
这里已经提出的大多数问题都是关于他们的 ControllerAdvice 实现不起作用。这个可行,但我想将其限制为处理应用程序代码引发的异常,而不是框架。
【问题讨论】:
-
如果您只想记录错误,为什么不使用过滤器并在 finally 块中记录错误?
-
@SarahCassar 这个例子非常简单。在实际应用程序中,ControllerAdvice 类已经有几个方法来处理更具体的异常。如果可能,我想将所有错误处理保留在一个类中。如果没有其他选择,我会尝试的。但希望它不会最终记录 Spring 抛出的异常。
-
异常处理的顺序是什么?如果您在有机会解决其他异常之前捕获 RuntimeException,则可能会发生这种情况。尝试减少此控制器建议的顺序,同时删除 ResponseStatus 注释。如果仍然无法正常工作,请提供可重现的示例。
-
正如我在下面的回答中所说,尝试将 extends ResponseEntityExceptionHandler 添加到您的 ControllerExceptionHandler ;-)
-
嗨@SarahCassar。我最终同意了你的建议。如果您愿意,请创建一个答案,以便我接受。我意识到该应用程序已经有一个过滤器来记录请求及其响应。实际上,这个过滤器没有记录由于未捕获的异常而失败的请求,因为它没有 try/catch。所以修复这个问题并在那里记录异常是最有意义的。
标签: java spring spring-boot