springboot-- 錯誤處理原理&定制錯誤頁面

1) springboot默認的錯誤處理機制

默認效果:
  1) 瀏覽器, 返回一個默認的錯誤頁面

     
springboot默認錯誤頁面.png

  2) 如果是其他客戶端,默認響應一個json數(shù)據(jù).

原理:

可以參照ErrorMvcAutoConfiguration:錯誤處理的自動配置
a. DefaultErrorAttributes

@Override
    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;
    }

b. BasicErrorController:處理/error請求

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

// 產(chǎn)生html類型的數(shù)據(jù);瀏覽器發(fā)送的請求來到這處理
    @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, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
//去哪個頁面作為錯誤頁面,包含頁面地址和頁面內(nèi)容
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }
// 產(chǎn)生json數(shù)據(jù)
    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);
        return new ResponseEntity<>(body, status);
    }

c. ErrorPageCustomizer

public class ErrorProperties {
  //  系統(tǒng)出現(xiàn)錯誤后來到error請求進行處理遗遵;(web.xml注冊的錯誤頁面規(guī)則)
    /**
     * Path of the error controller.
     */
    @Value("${error.path:/error}")
    private String path = "/error";

d. 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);
        }
// 模板引擎不可用,就在靜態(tài)資源文件夾下找errorViewName對應的頁面
        return resolveResource(errorViewName, model);
    }

步驟: 
   一旦系統(tǒng)出現(xiàn)4xx或者5xx的錯誤: ErrorPageCustomizer生效(定制錯誤的響應規(guī)則)拷恨,就會來到/error請求舔亭, BasicErrorController進行處理些膨,

  1. 響應頁面:去哪個頁面是由defaultErrorViewResolver
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;
    }

2) 如何定制錯誤響應

  1. 如何定制錯誤頁面
      1) 有模板引擎情況,error/404.html [將錯誤頁面命名為錯誤狀態(tài)碼.html放在模板引擎文件里的error文件夾下]钦铺,發(fā)生此狀態(tài)碼的錯誤就會來到對應的頁面.
       我們可以使用4xx和5xx命名的錯誤頁面來匹配這種類型的錯誤订雾,精確優(yōu)先(優(yōu)先尋找精確的狀態(tài)碼.html)
       可以獲取到的信息:
       timestamp:時間戳
       status:狀態(tài)碼
       error:錯誤提示
       exception:異常
       message:異常信息
       errors:JSR303數(shù)據(jù)校驗的錯誤都在這里

    2) 沒有模板引擎,去靜態(tài)資源下尋找
    3) 以上都沒有矛洞,來到springboot的默認空白頁面

  1. 如何定制錯誤的json數(shù)據(jù)
    a. 自定義異常處理洼哎,返回定制的json數(shù)據(jù)
@ResponseBody
@ControllerAdvice
public class MyExceptionHandler  {

    @ExceptionHandler(UserNotExistException.class)
    public Map<String, Object> handlerException(Exception e){
        Map<String,Object> map = new HashMap<>();
        map.put("codes","user.notExist");
        map.put("message",e.getMessage());
        return map;
    }
}
// 沒有自適應效果,不管是其他客戶端還是瀏覽器都是返回json數(shù)據(jù)

b. 轉(zhuǎn)發(fā)到/error進行自適應響應效果處理


 @ExceptionHandler(UserNotExistException.class)
    public String handlerException(Exception e, HttpServletRequest req) {
        Map<String, Object> map = new HashMap<>();
//        傳入自己的狀態(tài)嗎,
        req.setAttribute("javax.servlet.error.status_code",500);
        map.put("codes", "用戶出錯了");
        map.put("message", e.getMessage());
        return "forward:/error";
    }

c. 將我們的定制數(shù)據(jù)攜帶出去
出現(xiàn)錯誤以后噩峦,會來到/error請求锭沟,會被BasicErrorController處理,響應出去可以獲取的數(shù)據(jù)识补,是由getErrorAttributes得到的(是由AbstractErrorController(ErrorController)規(guī)定的方法)

  1. 完全編寫一個ErrorController的實現(xiàn)類[或者是編寫AbstractErrorController的子類]族淮,放在容器中
  2. 第二種,頁面上能用的數(shù)據(jù)李请,或者是json返回能用的數(shù)據(jù)都是通過errorAttributes得到;容器中DefaultErrorAttributes默認進行數(shù)據(jù)處理的.
    自定義


    @ExceptionHandler(UserNotExistException.class)
    public String handlerException(Exception e, HttpServletRequest req) {
        Map<String, Object> map = new HashMap<>();
//        傳入自己的狀態(tài)嗎厉熟,
        req.setAttribute("javax.servlet.error.status_code",500);
        map.put("codes", "用戶出錯了");
        map.put("message", e.getMessage());
        req.setAttribute("mm",map);
        return "forward:/error";
    }

@Component
public class MyErrorAttributes extends DefaultErrorAttributes {

       @Override
    public Map<String, Object> getErrorAttributes(WebRequest request, boolean includeStackTrace) {
        Map<String, Object> map = super.getErrorAttributes( request,includeStackTrace);
        map.put("say","靳飛虎导盅,大笨蛋");
        Map<String,Object> mm = (Map)  request.getAttribute("mm", 0);
        map.put("message",mm);
        return map;

    }
}

最終的效果,響應是自適應的揍瑟,可以通過定制ErrorAttributes改變需要返回的內(nèi)容.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末白翻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绢片,更是在濱河造成了極大的恐慌滤馍,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件底循,死亡現(xiàn)場離奇詭異巢株,居然都是意外死亡,警方通過查閱死者的電腦和手機熙涤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門阁苞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人祠挫,你說我怎么就攤上這事那槽。” “怎么了等舔?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵骚灸,是天一觀的道長。 經(jīng)常有香客問我慌植,道長甚牲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任蝶柿,我火速辦了婚禮鳖藕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘只锭。我一直安慰自己著恩,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喉誊,像睡著了一般邀摆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伍茄,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天栋盹,我揣著相機與錄音,去河邊找鬼敷矫。 笑死例获,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的曹仗。 我是一名探鬼主播榨汤,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼怎茫!你這毒婦竟也來了收壕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤轨蛤,失蹤者是張志新(化名)和其女友劉穎蜜宪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祥山,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡圃验,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缝呕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片损谦。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖岳颇,靈堂內(nèi)的尸體忽然破棺而出照捡,到底是詐尸還是另有隱情,我是刑警寧澤话侧,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布栗精,位于F島的核電站,受9級特大地震影響瞻鹏,放射性物質(zhì)發(fā)生泄漏悲立。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一新博、第九天 我趴在偏房一處隱蔽的房頂上張望薪夕。 院中可真熱鬧,春花似錦赫悄、人聲如沸原献。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姑隅。三九已至写隶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讲仰,已是汗流浹背慕趴。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鄙陡,地道東北人冕房。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像趁矾,于是被迫代替她去往敵國和親耙册。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容