SpringBoot错误处理
对于SpringBoot的错误处理,一般用HandlerExceptionResolver或@ExceptionHandler接收异常信息,做进一步处理。
对于没有处理的则直接返回错误页面。
HandlerExceptionResolver
可以捕获Handler中的异常,做自定义处理
配合@ControllerAdvice使用
ErrorPage
ErrorPageFilter BasicErrorController 什么关系
产生处理错误流程
ResourceHttpRequestHandler 拦截 /** 所有路径
在ResourceHttpRequestHandler.handleRequest 处理时 如果获取不到resource就设置responseStatus为404。

tomcat收到response为404,dispatch到/error页面。
通常有以下几种错误页面
- 自定义的错误页面

- SpringBoot的错误页面

- Tomcat的错误页面

ErrorPage原理
ErrorPage从哪来的呢?
/error 在Tomcat中定义
1. ErrorPageCustomizer中定义"/error" ErrorPage
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {
private final ServerProperties properties;
protected ErrorPageCustomizer(ServerProperties properties) {
this.properties = properties;
}
@Override
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix()
+ this.properties.getError().getPath());//这里就是“/error”
errorPageRegistry.addErrorPages(errorPage);
}
@Override
public int getOrder() {
return 0;
}
}
2. ErrorMvcAutoConfiguration配置ErrorPageRegistrar(ErrorPageCustomizer)
ErrorMvcAutoConfiguration 中配置ErrorPageCustomizer
@Bean
public ErrorPageCustomizer errorPageCustomizer() {
return new ErrorPageCustomizer(this.serverProperties);
}
3. ErrorPageRegistrarBeanPostProcessor 处理ErrorPageRegistry?
registerErrorPages 在ErrorPageRegistrarBeanPostProcessor 中被调用,注册给ErrorPageRegistry。

ErrorPageFilter是针对非嵌入容器的。
4. WebApplicationContext.onRefresh()中createWebServer()注册ErrorPage
最终在WebApplicationContext.onRefresh() 方法中要createWebServer(),创建内嵌的Tomcat。
通过TomcatEmbeddedServletContainerFactory(SpringBoot1.5有),将ErrorPage注册到context中(StandardContext)。
for (ErrorPage errorPage : getErrorPages()) {
new TomcatErrorPage(errorPage).addToContext(context);
}
tomcat转到/error页面
上面文章介绍的很清楚。
先从StandardContext中获取到ErrorPage。
ErrorPage errorPage = context.findErrorPage(statusCode);
if (errorPage == null) {
// Look for a default error page
errorPage = context.findErrorPage(0);
}
根据errorPage获取到Dispatcher,然后forward到地址("/error")
RequestDispatcher rd = servletContext.getRequestDispatcher(errorPage.getLocation());
...
rd.forward(request.getRequest(), response.getResponse());
如果没有配置errorPage就是下面这样子。

/error页面SpringBoot处理
产生错误,交给tomcat,tomcat dispatcher到 /error页面
response.sendError(HttpServletResponse.SC_NOT_FOUND); 只是设置状态,Exception为null,ExceptionResolver不处理。
最后被tomcat处理,转到“/error”页面。
SpringBoot自带的 /error页面
就是第二种错误页面

在ErrorMvcAutoConfiguration 中会自动配置BasicErrorController,BasicErrorController处理/error页面。BasicErrorController配置view为“error”。
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
}
同样在ErrorMvcAutoConfiguration中配置了name = error的view。
resolveErrorView 用到了ErrorViewResolver,也可以自定义ErrorViewResolver。
@Configuration
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
@Conditional(ErrorTemplateMissingCondition.class)
protected static class WhitelabelErrorViewConfiguration {
private final SpelView defaultErrorView = new SpelView(
"<html><body><h1>Whitelabel Error Page</h1>"
+ "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"
+ "<div id='created'>${timestamp}</div>"
+ "<div>There was an unexpected error (type=${error}, status=${status}).</div>"
+ "<div>${message}</div></body></html>");
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {
return this.defaultErrorView;
}
}
如果不想使用Springboot自带的Error可以不去加载ErrorMvcAutoConfiguration
@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
自定义ErrorPage的配置方式
SpringBoot自带的错误页面太丑了。可以自定义。
方式一:添加ErrorPage
老:
@Configuration
public class ErrorPageConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/static/html/500.html");
ErrorPage error500Page = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/static/html/500.html");
container.addErrorPages(error404Page, error500Page);
}
};
}
}
新:
@Configuration
public class ContainerConfig implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
ErrorPage[] errorPages = new ErrorPage[2];
errorPages[0] = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
errorPages[1] = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
registry.addErrorPages(errorPages);
}
}
方式二:重写名字为Error的View
定义view
public class GunsErrorView implements View {
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
httpServletRequest.getRequestDispatcher("/global/error").forward(httpServletRequest, httpServletResponse);
}
}
配置error view
@Bean("error")
public GunsErrorView error() {
return new GunsErrorView();
}
方式三:自定义ErrorViewResolver
ErrorViewResolver在BasicErrorController中被使用。返回ModelAndView。
...
SpringBoot错误处理
对于SpringBoot的错误处理,一般用HandlerExceptionResolver或@ExceptionHandler接收异常信息,做进一步处理。
对于没有处理的则直接返回错误页面。
HandlerExceptionResolver
可以捕获Handler中的异常,做自定义处理
@ExceptionHandler
配合@ControllerAdvice使用
ErrorPage
ErrorPageFilter BasicErrorController 什么关系
产生处理错误流程
ResourceHttpRequestHandler 拦截 /** 所有路径

在ResourceHttpRequestHandler.handleRequest 处理时 如果获取不到resource就设置responseStatus为404。
tomcat收到response为404,dispatch到/error页面。
通常有以下几种错误页面
ErrorPage原理
ErrorPage从哪来的呢?
/error 在Tomcat中定义
tomcat转到/error页面
上面文章介绍的很清楚。
先从StandardContext中获取到ErrorPage。
根据errorPage获取到Dispatcher,然后forward到地址("/error")
如果没有配置errorPage就是下面这样子。

/error页面SpringBoot处理
产生错误,交给tomcat,tomcat dispatcher到 /error页面
response.sendError(HttpServletResponse.SC_NOT_FOUND); 只是设置状态,Exception为null,ExceptionResolver不处理。
最后被tomcat处理,转到“/error”页面。
SpringBoot自带的 /error页面
就是第二种错误页面

在ErrorMvcAutoConfiguration 中会自动配置BasicErrorController,BasicErrorController处理/error页面。BasicErrorController配置view为“error”。
同样在ErrorMvcAutoConfiguration中配置了name = error的view。
resolveErrorView 用到了ErrorViewResolver,也可以自定义ErrorViewResolver。
如果不想使用Springboot自带的Error可以不去加载ErrorMvcAutoConfiguration
自定义ErrorPage的配置方式
SpringBoot自带的错误页面太丑了。可以自定义。
方式一:添加ErrorPage
老:
新:
方式二:重写名字为Error的View
定义view
配置error view
方式三:自定义ErrorViewResolver
ErrorViewResolver在BasicErrorController中被使用。返回ModelAndView。
...