43.SpringBoot學習筆記–錯誤處理原理與定製錯誤頁面
錯誤處理機制
Spring Boot 默認的錯誤處理機制
1、瀏覽器返回一個默認的錯誤頁面;
BasicErrorController 根據瀏覽器的請求頭識別出是瀏覽器訪問
2、如果是其他客戶端,默認響應一個 json 數據
根據其他客戶端發送的請求頭識別出是非瀏覽器訪問
原理:
一但系統出現 4xx 或者 5xx 之類的錯誤,ErrorPageCustomizer 就會生效(ErrorPageCustomizer),請求 /error,被 BasicErrorController 處理。
響應頁面:
org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController#resolveErrorView
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,
Map<String, Object> model) {
//所有的ErrorViewResolver得到ModelAndView
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
去哪個頁面是由 DefaultErrorViewResolver 解析得到的。
參考:
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
給容器中添加了以下組件
1、DefaultErrorAttributes:
org.springframework.boot.web.servlet.error.DefaultErrorAttributes#getErrorAttributes
幫我們在頁面共享信息
@Override
@Deprecated
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, webRequest);
addErrorDetails(errorAttributes, webRequest, includeStackTrace);
addPath(errorAttributes, webRequest);
return errorAttributes;
}
2、BasicErrorController:處理默認 /error 請求
org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {}
org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#errorHtml
//產生html類型的數據,瀏覽器發送的請求,到這個方法處理
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
//去哪個頁面作爲錯誤頁面,包含頁面地址和頁面內容
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
org.springframework.http.MediaType#TEXT_HTML_VALUE
/**
* A String equivalent of {@link MediaType#TEXT_HTML}.
*/
public static final String TEXT_HTML_VALUE = "text/html";
org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error
////產生json數據,其他客戶端到這個方法處理;
@RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity<>(status);
}
Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
3、ErrorPageCustomizer:
系統出現錯誤後,來到 error 請求進行處理(類似 web.xml 註冊的錯誤頁面規則)
org.springframework.boot.autoconfigure.web.ErrorProperties#path
@Value("${error.path:/error}")
private String path = "/error";
4、DefaultErrorViewResolver:
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//默認SpringBoot可以去找到error/404這個頁面
String errorViewName = "error/" + viewName;
//如果模板引擎可以解析這個頁面地址,就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
this.applicationContext);
if (provider != null) {
//模板引擎可用的情況下,返回到errorViewName指定的視圖地址
return new ModelAndView(errorViewName, model);
}
//模板引擎不可用,就在靜態資源文件夾下找errorViewName對應的頁面,也就是error/404.html
return resolveResource(errorViewName, model);
}
定製錯誤處理機制
有模板引擎的情況下,將錯誤頁面命名爲 “錯誤狀態碼.html” 放在模板引擎文件夾裏面的 error 文件夾下,也就是 error/狀態碼.html。 發生此狀態碼的錯誤就會來到對應的頁面。
可以使用 4xx 和 5xx 作爲錯誤頁面的文件名來匹配這種類型的所有錯誤。在有精確的 “狀態碼.html” ,精確優先。
頁面能獲取的信息:
- timestamp:時間戳
- status:狀態碼
- error:錯誤提示
- exception:異常對象(經本人驗證 Spring Boot v2.3.0 中無法獲取)
- message:異常消息(經本人驗證 Spring Boot v2.3.0 中無法獲取)
- errors:JSR303 數據校驗的錯誤都在這裏(經本人驗證 Spring Boot v2.3.0 中無法獲取)
頁面獲取信息示例:
<h1>status: [[${status}]]</h1>
<h2>timestamp: [[${timestamp}]]</h2>
2、沒有模板引擎,也就是模板引擎找不到這個錯誤頁面,靜態資源文件夾下找;
3、以上目錄都找不到錯誤頁面,就來到 Spring Boot 默認的錯誤提示頁面。