擴展sentinel之錯誤頁面

1.天象異常!

應用接入sentinel dashboard後,針對端點:/sentinel/grade/{userId}

1.1.配置流控規則

訪問端點:http://127.0.0.1:8080/sentinel/grade/1,瘋狂刷新!流控了!

注意:發生流控後,提示的消息是【Blocked by Sentinel (flow limiting)】

1.2.配置熔斷規則

避免干擾,刪除前面配置的流控規則,針對端點:/sentinel/grade/{userId},配置一個熔斷規則

訪問端點:http://127.0.0.1:8080/sentinel/grade/1,瘋狂刷新!熔斷了!

注意:發生熔斷後,提示的消息是【Blocked by Sentinel (flow limiting)】

總結,有沒有發現,不管是發生流控,還是熔斷後,提示的信息都是【Blocked by Sentinel (flow limiting)】,見鬼了!到底是流控,還是熔斷呢?請你告訴我!

1.3.透過現象看本質

前面通過案例,發現不管是發生流控,還是發生熔斷,系統給的默認提示信息都是一樣的,難以區分!那麼這個提示信息是從哪裏來的呢?

查看源碼,我們發現sentinel在保護資源時,比如說超出了流控閾值,或者熔斷閾值,都是拋出異常的處理方式進行處理,該異常是:BlockException,它有相應的規則子類異常,圖示

那麼當拋出BlockException異常後,是有誰來處理的呢?sentinel提供了一個處理接口

public interface BlockExceptionHandler {
    void handle(HttpServletRequest var1, HttpServletResponse var2, BlockException var3) throws Exception;
}

以及一個默認的實現

public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
    public DefaultBlockExceptionHandler() {
    }

    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setStatus(429);
        PrintWriter out = response.getWriter();
        // 剛纔傻傻分不清的提示信息,就是從這裏來的了!
        out.print("Blocked by Sentinel (flow limiting)");
        out.flush();
        out.close();
    }
}

2.擴展BlockExceptionHandler

理解底層處理機制後,解決問題就非常簡單了!我們只需要擴展BlockExceptionHandler接口,替換默認實現即可。來試一下吧!

2.1.封裝消息SentinelMsg

@Data
public class SentinelMsg {

    private int status;
    private String msg;
}

2.2.擴展BlockExceptionHandler

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {

    /**
     * 重寫handle方法
     * @param request
     * @param response
     * @param e
     * @throws Exception
     */
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       BlockException e) throws Exception {

        // 1.狀態碼,以及提示消息
        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        String errorMsg = "sentinel 未知異常!";

        // 2.判斷處理異常
        if(e instanceof FlowException){
            status = HttpStatus.TOO_MANY_REQUESTS.value();
            errorMsg = "error,限流了!";
        }else if(e instanceof DegradeException){
            errorMsg = "error,降級了!";
        }else if(e instanceof ParamFlowException){
            status = HttpStatus.TOO_MANY_REQUESTS.value();
            errorMsg = "error,熱點參數限流了!";
        }else if(e instanceof AuthorityException){
            errorMsg = "error,沒有訪問權限!";
        }else if(e instanceof SystemBlockException){
            errorMsg = "error,系統資源不夠了!";
        }

        // 3.設置響應
        response.setStatus(status);
        response.setContentType("application/json;charset=utf-8");
        SentinelMsg sentinelMsg = new SentinelMsg();
        sentinelMsg.setStatus(status);
        sentinelMsg.setMsg(errorMsg);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(response.getOutputStream(),sentinelMsg);
    }
}

3.測試效果

訪問端點:http://127.0.0.1:8080/sentinel/grade/1,測試流控,提示消息

{"status":429,"msg":"error,限流了!"}

訪問端點:http://127.0.0.1:8080/sentinel/grade/1,測試熔斷,提示消息

{"status":500,"msg":"error,降級了!"}

這樣一來,就實現了sentinel不同規則下,不同異常消息提示了。

 

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