在使用 Spring Boot
若是出現錯誤會出現 Whitelabel Error Page
頁面,這個是 Spring Boot
默認處理錯誤的一個頁面,是一硬編碼的形式建立的。咱們能夠替換調,使用本身的error頁面,而且美化它。html
網上也有不少相似的文章,不過看了不少有的不全面、有的根本就是錯誤的(好比設置server.error.whitelabel.enabled=false
添加error.html
,這是有前提的), 今天咱們從源碼的角度來分析它並給出解決方案。java
首選Spring Boot
若是出現錯誤,好比:500
、503
、404
等,均是有 org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
處理的,咱們也能夠重寫它(若是你重寫了它,你會驚奇的發現:下面的內容是多餘的,哈哈)實現本身的邏輯;
web
從圖上能夠看出 Spring Boot
想的很周全,同步和異步均有處理,這裏咱們只討論同步的問題, 由於只有同步會出現Whitelabel Error Page
spring
咱們定位到解析視圖的那句代碼緩存
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
resolveErrorView
是由父類AbstractErrorControllers
實現 app
ErrorViewResolver
的默認實現是 DefaultErrorViewResolver
異步
從resolve
方法中咱們能夠拆分一下幾步 一、找到可用的模版引擎提供者ide
假如出現的錯誤是
500
則此時errorViewName="error/500"
spring-boot
查找邏輯交給了TemplateAvailabilityProviders
類的getProvider
方法,此方法會緩存已經存在的模板引擎提供者, 具體由findProvider
去查找,若findProvider
也沒找到會默認註冊一個NoTemplateAvailabilityProvider
ui
注意 this.providers
這是 Spring Boot
在容器啓動的時候就會添加的,經過模板引擎類名是否存在來判斷是否添加某個的模板引擎提供者,默認Spring Boot
會註冊一下幾個模板引擎提供者;
加載模板引擎提供者
loadFactories
加載的是spring-boot-autoconfigure-2.xxxx.jar
下面的META-INF/spring.factories
, 此方法能夠獲取父類全部的實現類
這裏以ThymeleafTemplateAvailabilityProvider
爲例
從圖中能夠看出找的是classpath:/templates/error/500.html
因此若出現500
錯誤咱們能夠在src/main/resources/
下新建目錄templates/error
在新建一個thymeleaf
的500.html
模板就能夠了;404
錯誤同理
從這裏咱們不難看出若想成功找到錯誤模板必須知足一下條件
- 類路徑存在模板引擎的
jar
classpath
下存在存在當前錯誤模板(例:500.html)
二、若第1步中的provider
找到則不用繼續下一步,直接返回找到的視圖
三、若第1步中沒有知足條件的provider
則交給resolveResource
處理;咱們來看看resolveResource
的邏輯
這一步主要的直接獲取靜態的html
;通常500
和404
能夠直接使用靜態的HTML
資源展現一個友好的提示便可,因此這裏直接獲取靜態的資源文件 默認查找位置以下
能夠經過配置改變
假如出現的錯誤是500
,查找結果如圖;咱們只須要建立資源文件,就能夠訪問<staticLocations>/error/5xx.html
四、若是以上三步都沒知足,怎麼辦?從BasicErrorController
中能夠看到最後會有個error
默認view,就會去找classpath:/templates/error.html
,處理邏輯同上;若是依然找不到Spring Boot
就會默認交給 ErrorMvcAutoConfiguration
中的 StaticView
去渲染
前提是
server.error.whitelabel.enabled=true
private static class StaticView implements View { 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; } 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"; } }
這就是 Whitelabel Error Page
來源
綜上所述,共有以下解決方案
若項目中使用了模板引擎 好比
thymeleaf
freemarker
此時server.error.whitelabel.enabled
關閉和開啓無關
classpath
下新建模板 /templates/error/5xx.html
/templates/error/4xx.html
classpath
下新建靜態資源 /<staticlocation>/error/5xx.html
/<staticlocation>/error/4xx.html
classpath
下直接新建模板 /templates/error.html
若項目中沒有任何模板引擎
server.error.whitelabel.enabled=true
使用內置view
渲染,出現Whitelabel Error Page
server.error.whitelabel.enabled=false
將不會有任何信息若以上有不懂或錯誤,能夠留言 碼專不易,轉載註明出處
關注WX公衆號,精彩不容錯過