首页 > 解决方案 > 正确使用 Spring Boot 的 ErrorController 和 Spring 的 ResponseEntityExceptionHandler

问题描述

问题

在 Spring Boot 中创建控制器以自定义方式处理所有错误/异常时,包括自定义异常,应该首选哪种技术?

  1. 控制器是否应该实现 Spring Boot 的ErrorController

  2. 控制器是否应该扩展 Spring 的ResponseEntityExceptionHandler

  3. 两者:一个控制器实现和扩展这两个类,包括它们的两个功能?

  4. 两者:两个独立的控制器,一个实现ErrorController,另一个扩展ResponseEntityExceptionHandler

目标

这篇文章的原因是在 Spring Boot 中找到一种具有以下所有属性的异常处理方法:

更多细节

我注意到两个控制器(参见上面的 1 和 2)都可能包含返回ResponseEntity对象的方法,从而处理发生的异常并向客户端返回响应。所以理论上他们可以产生相同的结果吗?

有几个关于使用技术 1 和 2 的教程。但我发现没有文章考虑这两个选项,比较它们或一起使用它们,这引发了几个额外的问题:

  1. 他们甚至应该一起考虑吗?

  2. 这两种提议的技术之间的主要区别是什么?有什么相似之处?

  3. 一个是另一个更强大的版本吗?有没有一个人可以做而另一个人不能做的事情,反之亦然?

  4. 它们可以一起使用吗?有没有必要这样做的情况?

  5. 如果它们一起使用,将如何处理异常?它是通过两个处理程序还是一个处理程序?在后者的情况下,是哪一个?

  6. 如果它们一起使用,并且在异常处理期间在控制器内部(一个或另一个)抛出异常,该异常将如何处理?它是否发送到另一个控制器?理论上异常会开始在控制器之间反弹或创建其他类型的不可恢复循环吗?

  7. 是否有任何关于 Spring Boot 如何在ResponseEntityExceptionHandler内部使用 Spring 或它如何期望它在 Spring Boot 应用程序中使用的可信/官方文档?

  8. 如果ResponseEntityExceptionHandler一个人就足够了,那为什么还要ErrorController存在呢?

将 SpringResponseEntityExceptionHandler@ExceptionHandler注解一起看时,它在分别处理不同类型的异常和使用更简洁的代码方面似乎更强大。但是因为 Spring Boot 是建立在 Spring 之上的,这是否意味着:

编辑:相关:Spring @ControllerAdvice vs ErrorController

标签: javaspringspring-bootexceptionerror-handling

解决方案


Spring Boot 应用程序具有用于错误处理的默认配置 - ErrorMvcAutoConfiguration

如果没有提供额外的配置,它的基本作用是:

  • 它创建默认的全局错误控制器 - BasicErrorController
  • 它创建默认的“错误”静态视图“Whitelabel 错误页面”。

BasicErrorController默认连接到“/error”。如果应用程序中没有自定义的“错误”视图,则在任何控制器抛出异常的情况下,用户会登陆 /error whitelabel 页面,该页面由 BasicErrorController 填充信息。

如果应用程序有一个实现ErrorController它的控制器,它将替换 BasicErrorController.

如果错误处理控制器中发生任何异常,它将通过 Spring 异常过滤器(请参阅下面的更多详细信息),最后如果没有发现该异常将由底层应用程序容器(例如 Tomcat)处理。底层容器将处理异常并根据其实现显示一些错误页面/消息。

BasicErrorController javadoc中有一条有趣的信息:

基本的全局错误控制器,渲染 ErrorAttributes。可以使用 Spring MVC 抽象(例如@ExceptionHandler)或通过添加 servlet 服务器错误页面来处理更具体的错误。

BasicErrorControllerErrorController实现是一个全局错误处理程序。它可以与@ExceptionHandler 结合使用。

这里我们来到ResponseEntityExceptionHandler

@ControllerAdvice 类的方便基类,希望通过 @ExceptionHandler 方法在所有 @RequestMapping 方法中提供集中式异常处理。这个基类提供了一个 @ExceptionHandler 方法来处理内部 Spring MVC 异常。

换句话说,这意味着它ResponseEntityExceptionHandler只是一个便利类,它已经包含了 Spring MVC 异常处理。我们可以将它用作自定义类的基类来处理控制器的异常。为了使我们的自定义类正常工作,它必须使用@ControllerAdvice.

带有注释的类@ControllerAdvice可以与全局错误处理程序(BasicErrorControllerErrorController实现)同时使用。如果我们的带@ControllerAdvice注释的类(可以/不可以扩展ResponseEntityExceptionHandler)不处理某些异常,则异常会转到全局错误处理程序。

到目前为止,我们查看了ErrorHandler控制器和任何用@ControllerAdvice. 但这要复杂得多。我在这个问题中发现了一个非常有价值的见解 - Setting Precedence of Multiple @ControllerAdvice @ExceptionHandlers

编辑:

为了简单起见:

  1. 首先 Spring 在 @ControllerAdvice 类中搜索异常处理程序(使用 @ExceptionHandler 注释的方法)。请参阅ExceptionHandlerExceptionResolver
  2. 然后它检查抛出的异常是用@ResponseStatus 注释还是从ResponseStatusException 派生。请参阅ResponseStatusExceptionResolver
  3. 然后它通过 Spring MVC 异常的默认处理程序。请参阅DefaultHandlerExceptionResolver
  4. 最后,如果没有找到,控件将被转发到错误页面视图,并在其后面带有全局错误处理程序。如果异常来自错误处理程序本身,则不执行此步骤。
  5. 如果没有找到错误视图(例如禁用全局错误处理程序)或跳过第 4 步,则异常由容器处理。

推荐阅读