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不同規則下,不同異常消息提示了。