您好,登錄后才能下訂單哦!
本篇內容介紹了“Spring Boot統一異常處理能攔截所有的異常嗎”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
通常我們在Spring Boot中設置的統一異常處理只能處理Controller拋出的異常。有些請求還沒到Controller就出異常了,而這些異常不能被統一異常捕獲,例如Servlet容器的某些異常。今天我在項目開發中就遇到了一個,這讓我很不爽,因為它返回的錯誤信息格式不能統一處理,我決定找個方案解決這個問題。
Whitelabel Error Page
這類圖相信大家沒少見,Spring Boot 只要出錯,體現在頁面上的就是這個。如果你用Postman之類的測試出了異常則是:
{ "timestamp": "2021-04-29T22:45:33.231+0000", "status": 500, "message": "Internal Server Error", "path": "foo/bar" }
這個是怎么實現的呢?Spring Boot在啟動時會注冊一個ErrorPageFilter,當Servlet發生異常時,該過濾器就會攔截處理,將異常根據不同的策略進行處理:當異常已經在處理的話直接處理,否則轉發給對應的錯誤頁面。有興趣的可以去看下源碼,邏輯不復雜,這里就不貼了。
另外當一個 Servlet 拋出一個異常時,處理異常的Servlet可以從HttpServletRequest里面得到幾個屬性,如下:
異常屬性
我們可以從上面的幾個屬性中獲取異常的詳細信息。
通常Spring Boot出現異常默認會跳轉到/error進行處理,而/error的相關邏輯則是由BasicErrorController實現的。
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends AbstractErrorController { //返回錯誤頁面 @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); } // 返回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); } // 其它省略 }
而對應的配置:
@Bean @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT) public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) { return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().collect(Collectors.toList())); }
所以我們只需要重新實現一個ErrorController并注入Spring IoC就可以替代默認的處理機制。而且我們可以很清晰的發現這個BasicErrorController不但是ErrorController的實現而且是一個控制器,如果我們讓控制器的方法拋異常,肯定可以被自定義的統一異常處理。所以我對BasicErrorController進行了改造:
@Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class ExceptionController extends AbstractErrorController { public ExceptionController(ErrorAttributes errorAttributes) { super(errorAttributes); } @Override @Deprecated public String getErrorPath() { return null; } @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { throw new RuntimeException(getErrorMessage(request)); } @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { throw new RuntimeException(getErrorMessage(request)); } private String getErrorMessage(HttpServletRequest request) { Object code = request.getAttribute("javax.servlet.error.status_code"); Object exceptionType = request.getAttribute("javax.servlet.error.exception_type"); Object message = request.getAttribute("javax.servlet.error.message"); Object path = request.getAttribute("javax.servlet.error.request_uri"); Object exception = request.getAttribute("javax.servlet.error.exception"); return String.format("code: %s,exceptionType: %s,message: %s,path: %s,exception: %s", code, exceptionType, message, path, exception); } }
直接拋異常,簡單省力!凡是這里捕捉的到的異常大部分還沒有經過Controller,我們通過ExceptionController中繼也讓這些異常被統一處理,保證整個應用的異常處理對外保持一個統一的門面。
“Spring Boot統一異常處理能攔截所有的異常嗎”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。