文章目录
首先,官方doc是这样介绍error的:
For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message. For browser clients, there is a “whitelabel” error view that renders the same data in HTML format (to customize it, add a View that resolves to error) To replace the default behavior completely, you can implement ErrorController and register a bean definition of that type or add a bean of type ErrorAttributes to use the existing mechanism but replace the contents.
对于机器客户端(非浏览器)发生错误,会返回JSON数据格式的错误信息。
对于浏览器客户端发生错误,返回一个包含错误信息的"whitelabel"页面,如果想要定制,自己实现ErrorController即可。官方推荐:继承BasicErrorController。
The BasicErrorController can be used as a base class for a custom ErrorController. This is particularly useful if you want to add a handler for a new content type (the default is to handle text/html specifically and provide a fallback for everything else). To do so, extend BasicErrorController, add a public method with a @RequestMapping that has a produces attribute, and create a bean of your new type.
ErrorMvcAutoConfiguration 错误处理自动配置类
先了解一下springboot中有关错误处理的类为:ErrorMvcAutoConfiguration。
位置:package org.springframework.boot.autoconfigure.web.servlet.error;
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({
Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({
ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {
...
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
}
里面比较主要的类有:BasicErrorController 、ErrorPageCustomizer
ErrorPageCustomizer 错误页面定制器
源码如下:
//ErrorMvcAutoConfiguration.java
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
// 静态内部类,默认的错误页面配置
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
private final ServerProperties properties;
private final DispatcherServletPath dispatcherServletPath;
protected ErrorPageCustomizer(ServerProperties properties, DispatcherServletPath dispatcherServletPath) {
this.properties = properties;
this.dispatcherServletPath = dispatcherServletPath;
}
// 注册错误页面的响应规则
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
ErrorPage errorPage = new ErrorPage(
//[#2] 注意getPath()
this.dispatcherServletPath.getRelativePath(this.properties.getError().getPath()));
errorPageRegistry.addErrorPages(errorPage);
}
//...
}
继续往下点击看[#2]处源码,默认path为/error。
public class ErrorProperties {
/**
* Path of the error controller.
*/
@Value("${error.path:/error}")
private String path = "/error";
即系统出现错误以后会来到/error请求,进行处理;(类似web.xml注册的错误页面规则)
那么问题来了,通过ErrorPageCustomizer设置后,出现错误会来到/error请求,接下来给谁处理呢??—— BasicErrorController
BasicErrorController 默认处理/error请求控制器
一旦系统出现4xx或者5xx之类的错误 --> ErrorPageCustomizer就会生效(定制错误的响应规则) --> 就会来到/error请求 --> 就会被BasicErrorController处理;
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
上面的源码里,有两个没见过的东西:ErrorViewResolver、BasicErrorController。
既然是返回BasicErrorController,肯定要看一下源码:
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
// ${server.error.path:${error.path:/error}} 解释:
// 如果没有配置server.error.path,则使用error.path;如果error.path也没有配置,则使用/error
public