43.SpringBoot學習筆記--錯誤處理原理與定製錯誤頁面

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 默認的錯誤提示頁面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章