java - 正确使用Spring Boot的ErrorController和Spring的ResponseEntityExceptionHandler

标签 java spring spring-boot exception error-handling

问题

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

  • Controller 应该实现Spring Boot的ErrorController吗?
  • Controller 应该扩展Spring的ResponseEntityExceptionHandler吗?
  • 两者:实现和扩展两个类(包括它们的功能)的单个 Controller ?
  • 两者:两个单独的 Controller ,一个实现ErrorController,另一个扩展ResponseEntityExceptionHandler

  • 目标

    这篇文章的原因是要在Spring Boot中找到一种具有以下所有属性的异常处理方法:
  • 应该捕获在处理请求期间在 Controller /过滤器/拦截器中发生的所有Throwable
  • 在捕获Throwable的情况下,我们不想希望向客户端暴露任何堆栈跟踪或其他实现细节(除非以这种方式明确编码)。
  • 应该有可能按其类分别处理所有发生的Throwable。对于任何其他未指定的类型,可以指定默认响应。 (我肯定知道,这可以通过@ExceptionHandler来实现。但是ErrorController吗?)
  • 该代码应尽可能简洁明了,没有丑陋的解决方法或UB来实现此目标。

  • 更多细节

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

    那里有关于如何使用技术1和2的一些教程。但是我发现没有文章同时考虑这两种选择,比较它们或将它们一起使用,这引起了另外一些问题:
  • 是否应该将它们一起考虑?
  • 这两种提议的技术之间的主要区别是什么?有何相似之处?
  • 是另一个功能更强大的版本吗?是否有一个人可以做的事情,而另一个人却做不到呢?
  • 它们可以一起使用吗?在某些情况下有必要这样做吗?
  • 如果将它们一起使用,将如何处理异常?它是通过两个处理程序还是通过一个处理程序?在后者的情况下,哪个?
  • 如果将它们一起使用,并且在异常处理期间在 Controller (一个或另一个)中抛出异常,将如何处理该异常?是否发送到另一个 Controller ?从理论上讲,异常是否可以在 Controller 之间开始反弹或创建其他某种类型的非恢复循环?
  • 是否有关于Spring Boot如何在内部使用Spring的ResponseEntityExceptionHandler或希望如何在Spring Boot应用程序中使用的可信/官方文档?
  • 如果仅ResponseEntityExceptionHandler已经足够,那么为什么ErrorController存在?

  • 当一起查看Spring的ResponseEntityExceptionHandler@ExceptionHandler批注时,在单独处理不同类型的异常并使用更简洁的代码时,它似乎更强大。但是,因为Spring Boot是基于Spring构建的,所以这意味着:
  • 使用Spring Boot时,我们应该实现ErrorController而不是扩展ResponseEntityExceptionHandler
  • ErrorController可以做到ResponseEntityExceptionHandler所能做的一切,包括分别处理不同类型的异常吗?

  • 编辑:相关:Spring @ControllerAdvice vs ErrorController

    最佳答案

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

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

  • 它创建默认的全局错误 Controller -BasicErrorController
  • 它创建默认的“错误”静态 View “Whitelabel错误页面”。
  • BasicErrorController默认连接到'/error'。如果应用程序中没有自定义的“错误” View ,则在任何 Controller 抛出异常的情况下,用户将进入/error whitelabel页面,该页面由BasicErrorController填充信息。

    如果应用程序具有实现ErrorController的 Controller ,则替换 BasicErrorController

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

    Basic global error Controller, rendering ErrorAttributes. More specific errors can be handled either using Spring MVC abstractions (e.g. @ExceptionHandler) or by adding servlet server error pages.


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

    这里我们来到ResponseEntityExceptionHandler

    A convenient base class for @ControllerAdvice classes that wish to provide centralized exception handling across all @RequestMapping methods through @ExceptionHandler methods. This base class provides an @ExceptionHandler method for handling internal Spring MVC exceptions.



    换句话说,这意味着ResponseEntityExceptionHandler只是一个便利类,它已经包含Spring MVC异常处理。我们可以将其用作自定义类的基类,以处理 Controller 的异常。为了使我们的自定义类起作用,必须使用@ControllerAdvice对其进行注释。

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

    到目前为止,我们研究了ErrorHandler Controller 以及所有带有@ControllerAdvice注释的内容。但这要复杂得多。
    我在问题Setting Precedence of Multiple @ControllerAdvice @ExceptionHandlers中发现了一个非常有值(value)的见解。

    编辑:

    为简单起见:
  • First Spring在@ControllerAdvice类中搜索异常处理程序(用@ExceptionHandler注释的方法)。参见ExceptionHandlerExceptionResolver
  • 然后,它检查抛出的异常是用@ResponseStatus注释还是从ResponseStatusException派生。参见ResponseStatusExceptionResolver
  • 然后它通过Spring MVC异常的默认处理程序。参见DefaultHandlerExceptionResolver
  • 最后,如果未找到任何内容,则将控件转发到错误页面 View ,并在其后添加全局错误处理程序。如果异常来自错误处理程序本身,则不会执行此步骤。
  • 如果未找到错误 View (例如,禁用了全局错误处理程序)或跳过了步骤4,则该异常由容器处理。
  • 关于java - 正确使用Spring Boot的ErrorController和Spring的ResponseEntityExceptionHandler,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55101797/

    相关文章:

    javascript - 如何通过url传递特殊字符 '/'

    java - Spring Boot应用程序中的循环 View 路径异常

    java - 在一个对象上获取 HibernateProxy

    java - Gradle坚持下载一些依赖项(Android Studio)

    java - MongoDB Java 客户端自动故障转移失败

    java - 一些 Collection

    spring - Web 流异常 : No flow execution snapshot could be found with id '1'

    java - 如何在JPQL中随机选择10条记录?

    Spring Mqtt - 以编程方式将消息发布到多个主题

    java - Spring Boot/JUnit,为多个配置文件运行所有单元测试