【问题标题】:Make a ControllerAdvice error handler that ignores Spring Exceptions创建一个忽略 Spring 异常的 ControllerAdvice 错误处理程序
【发布时间】: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


【解决方案1】:

我认为来自https://reflectoring.io/spring-boot-exception-handling/#controlleradvice 的控制器建议实现 可能会解决您的问题。

ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
  @ExceptionHandler(RuntimeException.class)
  @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
  public ResponseEntity<Object> handleAllUncaughtException(
      RuntimeException exception, 
      WebRequest request
  ){
      //Log the exception and handle it here
  }

  @Override
  public ResponseEntity<Object> handleExceptionInternal(
      Exception ex,
      Object body,
      HttpHeaders headers,
      HttpStatus status,
      WebRequest request) {
      //Log the exception and handle it here
  }

}

基类 ResponseEntityExceptionHandler 包含标准 Spring 异常的异常处理程序。我读到弹簧首先处理来自控制器建议的大多数特定异常。如果出现弹簧错误,默认代码将处理它。如果发生运行时异常,您的处理程序将被执行。

【讨论】:

  • 你好。这个答案看起来很棒!我最终在问题的 cmets 中提出了一个建议,因为项目中的一些现有代码恰好适合这种方法。但如果不是这样,我相信这将是一个很好的解决方案。感谢您花时间研究我的问题。
猜你喜欢
  • 2016-03-25
  • 2018-01-15
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 2018-07-13
  • 2022-10-14
相关资源
最近更新 更多