一尘不染

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

spring-boot

问题

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

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

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

  3. 两者:实现和扩展两个类(包括它们的功能)的单个控制器?

  4. 两者:两个单独的控制器,一个执行ErrorController,另一个扩展ResponseEntityExceptionHandler

目标

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

  • Throwable在处理请求期间,所有出现在控制器/过滤器/拦截器中的信号都应被捕获。
  • 在受凉的情况下Throwable,我们 希望暴露任何堆栈跟踪或其他实施细则,以客户 永远 (除非明确编码的方式)。
  • 应该有可能Throwable按其类分别处理所有发生的。对于任何其他未指定的类型,可以指定默认响应。(我肯定知道,这 可以实现的@ExceptionHandler。但是ErrorController?)
  • 该代码应尽可能简洁明了,没有丑陋的解决方法或UB来实现此目标。

更多细节

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

那里有关于如何使用技术1和2的一些教程。但是,我发现没有文章同时考虑这两种选择,将它们进行比较或一起使用,这引发了一些其他问题:

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

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

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

  4. 它们可以一起使用吗?在某些情况下有必要这样做吗?

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

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

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

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

ResponseEntityExceptionHandler@ExceptionHandler注解一起查看Spring时,它似乎在分别处理不同类型的异常和使用更简洁的代码方面更强大。但是由于Spring
Boot是基于Spring构建的,因此这意味着:

  • 当使用Spring Boot时,我们应该实现ErrorController而不是扩展ResponseEntityExceptionHandler
  • 是否可以ErrorController做所有事情ResponseEntityExceptionHandler,包括分别处理不同类型的异常?

阅读 1001

收藏
2020-05-30

共1个答案

一尘不染

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

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

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

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

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

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

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

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

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

在这里,我们来到ResponseEntityExceptionHandler

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

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

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

到目前为止,我们已经看过ErrorHandler控制器以及任何带有注释的东西@ControllerAdvice

编辑:

为简单起见:

  1. First Spring在@ControllerAdvice类中搜索异常处理程序(以@ExceptionHandler注释的方法)。请参见ExceptionHandlerExceptionResolver
  2. 然后,它检查抛出的异常是使用@ResponseStatus注释还是从ResponseStatusException派生。请参见ResponseStatusExceptionResolver
  3. 然后,它通过Spring MVC异常的默认处理程序。请参见DefaultHandlerExceptionResolver
  4. 最后,如果未找到任何内容,则将控件转发到错误页面视图,并在其后面放置全局错误处理程序。如果异常来自错误处理程序本身,则不会执行此步骤。
  5. 如果未找到错误视图(例如,禁用了全局错误处理程序)或跳过了步骤4,则该异常由容器处理。
2020-05-30