SpringBoot全局異常處理捕獲Filter內部異常

通常在項目中都會使用到全局異常處理,但是如果添加有攔截器,對攔截器中的異常進行捕獲的時候,就會發現全局異常處理失效,無法對攔截器的異常進行捕獲。

全局異常不能捕獲攔截器異常的原因

SpringBoot下全局異常處理的幾種方式:

  1. BasicExceptionController——SpringBoot默認處理異常方式,用於異常跳轉到/error,可實現自定義錯誤頁面請求。
  2. @ExceptionHandle註解——只能在控制器中定義異常處理方法。
  3. @ControllerAdvice+@ExceptionHandler——增強控制前Controller實現異常攔截。
  4. SimpleMappingExceptionResolver——攔截異常跳轉到error頁面。
  5. HandlerExceptionResolver——實現HandlerExceptionResolver攔截異常。

上面幾種方式只能攔截到控制層的異常,而Filter在Controller之前,Controller層的異常捕獲,是無法捕獲到還沒有請求到Controller時發生的異常的。

實現對Filter異常的捕獲

從上面的幾種異常處理方式可以發現,如果要捕獲Filter異常,只能通過控制器層定義的全局異常處理來捕獲;那麼也就只能想辦法讓Filter中的異常發送到Controller,再由Controller拋出異常,最後由全局異常捕獲。
有了上面的思路,第一個要解決的問題就是怎麼讓過濾器中的異常在Filter中被捕獲到再發送出去。

Filter的實現方式是責任鏈,第一個Filter處理之後,調用第二個Filter,依次往後,直到Filter全部處理完成後結束;當某一個Filter處理中斷,則依次返回結果經過前一個Filter,直到經過第一個Filter過濾後結束過濾責任鏈。

根據Filter過濾的特點,只需要在業務過濾器之前加上用於處理其他過濾器異常捕獲的Filter就可以實現對過濾器異常的處理。

1 簡單實現異常過濾Filter代碼如下:

@Slf4j
@Component
public class ExceptionFilter implements Filter {
   
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
            // 異常捕獲,發送到error controller
            request.setAttribute("filter.error", e);
            //將異常分發到/error/exthrow控制器
            request.getRequestDispatcher("/error/exthrow").forward(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {

    }
}

2 註冊過濾器時,ExceptionFilter排序要再其他過濾器之前

 @Bean
    public FilterRegistrationBean exceptionFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(exceptionFilter);
        registration.setName("exceptionFilter");
        //此處儘量小,要比其他Filter靠前
        registration.setOrder(-1);
        return registration;
    }

3 實現Controller接收過過濾器發來的異常

@RestController
public class ErrorController {
    /**
     * 重新拋出異常
     */
    @RequestMapping("/error/exthrow")
    public void rethrow(HttpServletRequest request) {
        throw ((Exception) request.getAttribute("filter.error"));
    }
}

以上只是Demo示例,再實際使用中,攔截Filter儘量攔截具體的Exception。

發佈了7 篇原創文章 · 獲贊 4 · 訪問量 8653
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章