1. 默认配置
1.1 配置
根据错误码匹配,如下:
目录 | 访问优先级 | 目录配置 |
---|---|---|
classpath:/META-INF/resources/ | 最高 | /error/404.html 或 /error/4xx.html |
classpath:/resources/ | - | /error/404.html 或 /error/4xx.html |
classpath:/static/ | - | /error/404.html 或 /error/4xx.html |
classpath:/public/ | - | /error/404.html 或 /error/4xx.html |
2.2 调试过程:
- 在application.yml 里面将日志级别调为debug
logging:
level.org: DEBUG
-
访问一个不存在的资源
系统会打印如下日志:
: getResource(META-INF/resources/error/404.html)
--> Resource not found, returning null
: getResource(resources/error/404.html)
--> Resource not found, returning null
: getResource(static/error/404.html)
--> Resource not found, returning null
: getResource(public/error/404.html)
--> Resource not found, returning null
: getResource(META-INF/resources/error/4xx.html)
--> Resource not found, returning null
: getResource(resources/error/4xx.html)
: --> Resource not found, returning null
: getResource(static/error/4xx.html)
: --> Resource not found, returning null
: getResource(public/error/4xx.html)
: getResourceAsStream(public/error/4xx.html)
: Exiting from "ERROR" dispatch, status 404
- 详细日志:
2020-09-14 18:00:28.679 DEBUG 6720 --- [nio-8080-exec-8] o.a.t.util.http.Rfc6265CookieProcessor : Cookies: Parsing b[]: JSESSIONID=3768F0D323A90FB70F40609ECF80E636
2020-09-14 18:00:28.680 DEBUG 6720 --- [nio-8080-exec-8] o.a.catalina.connector.CoyoteAdapter : Requested cookie session id is 3768F0D323A90FB70F40609ECF80E636
2020-09-14 18:00:28.680 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.authenticator.AuthenticatorBase : Security checking request GET /index5.html
2020-09-14 18:00:28.681 DEBUG 6720 --- [nio-8080-exec-8] org.apache.catalina.realm.RealmBase : No applicable constraints defined
2020-09-14 18:00:28.681 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.authenticator.AuthenticatorBase : Not subject to any constraint
2020-09-14 18:00:28.682 DEBUG 6720 --- [nio-8080-exec-8] org.apache.tomcat.util.http.Parameters : Set encoding to UTF-8
2020-09-14 18:00:28.682 DEBUG 6720 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : GET "/index5.html", parameters={}
2020-09-14 18:00:28.685 DEBUG 6720 --- [nio-8080-exec-8] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2020-09-14 18:00:28.691 DEBUG 6720 --- [nio-8080-exec-8] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2020-09-14 18:00:28.691 DEBUG 6720 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND
2020-09-14 18:00:28.693 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2020-09-14 18:00:28.698 DEBUG 6720 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
2020-09-14 18:00:28.700 DEBUG 6720 --- [nio-8080-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml(HttpServletRequest, HttpServletResponse)
2020-09-14 18:00:28.723 DEBUG 6720 --- [nio-8080-exec-8] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.template.provider.cache' in PropertySource 'configurationProperties' with value of type String
2020-09-14 18:00:28.725 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(freemarker.template.Configuration)
2020-09-14 18:00:28.728 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.728 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(freemarker.template$Configuration)
2020-09-14 18:00:28.731 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.731 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(com.samskivert.mustache.Template)
2020-09-14 18:00:28.732 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.733 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(com.samskivert.mustache$Template)
2020-09-14 18:00:28.735 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.735 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(groovy.text.TemplateEngine)
2020-09-14 18:00:28.735 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.736 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(groovy.text$TemplateEngine)
2020-09-14 18:00:28.738 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.738 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.thymeleaf.spring5.SpringTemplateEngine)
2020-09-14 18:00:28.743 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.744 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.thymeleaf.spring5$SpringTemplateEngine)
2020-09-14 18:00:28.746 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.746 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.apache.jasper.compiler.JspConfig)
2020-09-14 18:00:28.748 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.749 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.apache.jasper.compiler$JspConfig)
2020-09-14 18:00:28.750 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.750 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(META-INF/resources/error/404.html)
2020-09-14 18:00:28.751 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.751 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.751 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(resources/error/404.html)
2020-09-14 18:00:28.751 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.751 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(static/error/404.html)
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(public/error/404.html)
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.752 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.753 DEBUG 6720 --- [nio-8080-exec-8] o.s.c.e.PropertySourcesPropertyResolver : Found key 'spring.template.provider.cache' in PropertySource 'configurationProperties' with value of type String
2020-09-14 18:00:28.753 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(freemarker.template.Configuration)
2020-09-14 18:00:28.753 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.754 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(freemarker.template$Configuration)
2020-09-14 18:00:28.754 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.756 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(com.samskivert.mustache.Template)
2020-09-14 18:00:28.758 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.758 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(com.samskivert.mustache$Template)
2020-09-14 18:00:28.759 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.760 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(groovy.text.TemplateEngine)
2020-09-14 18:00:28.760 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.762 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(groovy.text$TemplateEngine)
2020-09-14 18:00:28.762 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.762 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.thymeleaf.spring5.SpringTemplateEngine)
2020-09-14 18:00:28.763 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.764 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.thymeleaf.spring5$SpringTemplateEngine)
2020-09-14 18:00:28.764 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.764 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.apache.jasper.compiler.JspConfig)
2020-09-14 18:00:28.765 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.765 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : findClass(org.apache.jasper.compiler$JspConfig)
2020-09-14 18:00:28.765 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning ClassNotFoundException
2020-09-14 18:00:28.765 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(META-INF/resources/error/4xx.html)
2020-09-14 18:00:28.766 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.766 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.766 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(resources/error/4xx.html)
2020-09-14 18:00:28.766 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(static/error/4xx.html)
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Resource not found, returning null
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResource(public/error/4xx.html)
2020-09-14 18:00:28.767 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.768 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning 'file:/E:/%e5%ad%a6%e4%b9%a0%e8%b5%84%e6%96%99/vue/workspace/spring-boot-study/spring-boot-resources-study/target/classes/public/error/4xx.html'
2020-09-14 18:00:28.773 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : getResourceAsStream(public/error/4xx.html)
2020-09-14 18:00:28.773 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : Delegating to parent classloader org.springframework.boot.devtools.restart.classloader.RestartClassLoader@2e0c56f1
2020-09-14 18:00:28.774 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.loader.WebappClassLoaderBase : --> Returning stream from parent
2020-09-14 18:00:28.777 DEBUG 6720 --- [nio-8080-exec-8] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404
2020-09-14 18:00:28.778 DEBUG 6720 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Disabling the response for further output
2. 自定义配置
2.1 源码解读
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
- 错误页面配置
从源码分析,默认会调用 StaticView defaultErrorView = new StaticView();
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)
@Conditional(ErrorTemplateMissingCondition.class)
protected static class WhitelabelErrorViewConfiguration {
private final StaticView defaultErrorView = new StaticView();
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {
return this.defaultErrorView;
}
// If the user adds @EnableWebMvc then the bean name view resolver from
// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.
@Bean
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;
}
}
- StaticView 代码
/**
* Simple {@link View} implementation that writes a default HTML error page.
*/
private static class StaticView implements View {
private static final MediaType TEXT_HTML_UTF8 = new MediaType("text", "html", StandardCharsets.UTF_8);
private static final Log logger = LogFactory.getLog(StaticView.class);
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (response.isCommitted()) {
String message = getMessage(model);
logger.error(message);
return;
}
response.setContentType(TEXT_HTML_UTF8.toString());
StringBuilder builder = new StringBuilder();
Date timestamp = (Date) model.get("timestamp");
Object message = model.get("message");
Object trace = model.get("trace");
if (response.getContentType() == null) {
response.setContentType(getContentType());
}
builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
.append("<div id='created'>").append(timestamp).append("</div>")
.append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
.append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
if (message != null) {
builder.append("<div>").append(htmlEscape(message)).append("</div>");
}
if (trace != null) {
builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
}
builder.append("</body></html>");
response.getWriter().append(builder.toString());
}
private String htmlEscape(Object input) {
return (input != null) ? HtmlUtils.htmlEscape(input.toString()) : null;
}
private String getMessage(Map<String, ?> model) {
Object path = model.get("path");
String message = "Cannot render error page for request [" + path + "]";
if (model.get("message") != null) {
message += " and exception [" + model.get("message") + "]";
}
message += " as the response has already been committed.";
message += " As a result, the response may have the wrong status code.";
return message;
}
@Override
public String getContentType() {
return "text/html";
}
}
2.2 配置
根据上面源码分析,只要自己只要自定义一个View覆盖源码中的View即可,具体操作如下:
-
在application.yml中配置
server.error.whitelabel.enable = true #默认为true
-
自定义View
public class GlobalErrorView implements View {
@Override
public String getContentType() {
return MediaType.TEXT_HTML_VALUE;
}
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
request.getRequestDispatcher("/error.html").forward(request,response);
}
}
- 覆盖原来的View
@Configuration
public class GlobalErrorConfig {
@Bean("error")
public View error() {
return new GlobalErrorView();
}
}
- 启动服务后就会发现,原来的访问的“Whitelabel Error Page”配置页面,已经变成了自己定义的页面。
注意:
系统默认会找 /error/404.html ,没有找到会跳转到 error