我们在八、springCloudAlibaba-整合sentinel整合了sentinel,这里尝试直接用控制台试用下,并且进行自定义异常。
1、流量控制
从簇点链路中新增流量控制规则
可以看到,配置很简单,我们并没有对我们的业务代码进行影响,配置好后,我们尝试快速点击,发现会返回
Blocked by Sentinel (flow limiting)
那这怎么办呢?我们怎么返回自定义的异常呢?
2、自定义异常
这里有两种方式,一种是用我们之前的每个业务请求都自定义对应的异常,也就是用@SentinelResource注解,比如这次我们加上
@RequestMapping("/add")@SentinelResource(value = "add", blockHandler = "exceptionHandler")public String add(String id){return "新增订单成功"+id;}//自定义返回public String exceptionHandler(String id, BlockException ex) {// Do some log here.ex.printStackTrace();return "被限流了"+id;}
启动后,访问一下请求簇点链路就会有add这个资源名,然后我们再新增流控,发现返回了自定义异常。(注:这里的资源名不能再是/order/add ,不然不会生效的,具体原因后续如果看源码再分析)
上面这种加用注解的方式对我们的代码其实是有侵入的,所以我们可以自定义异常,也很简单,加上下面一个异常类即可,该异常类实现BlockExceptionHandler
package com.suibibk.springCloud.order;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;import com.alibaba.csp.sentinel.slots.block.BlockException;import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;import com.alibaba.csp.sentinel.slots.block.flow.FlowException;import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;import com.alibaba.fastjson.JSON;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.MediaType;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@Componentpublic class MyBlockExceptionHandler implements BlockExceptionHandler {Logger log = LoggerFactory.getLogger(this.getClass());public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {//getRule返回资源、规则的详细信息log.info("BlockExceptionHandler BlockException================"+e.getRule());Result r = null;if(e instanceof FlowException){r = Result.error(100,"接口被限流了");}else if (e instanceof DegradeException){r = Result.error(101,"服务降级了");}else if (e instanceof ParamFlowException){r = Result.error(102,"热点参数限流了");}else if (e instanceof AuthorityException){r = Result.error(104,"授权规则不通过");}//返回Json数据httpServletResponse.setStatus(500);httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);PrintWriter writer=null;try {writer=httpServletResponse.getWriter();writer.write(JSON.toJSONString(r));writer.flush();} catch (IOException ioException) {log.error("异常:{}",ioException);}finally {if(writer!=null) {writer.close();}}}}
统一返回封装
package com.suibibk.springCloud.order;public class Result<T> {private Integer code;private String msg;private T data;public Result(Integer code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}public Result(Integer code, String msg) {this.code = code;this.msg = msg;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}public static Result error(Integer code,String msg){return new Result(code,msg);}}
然后就不用加@SentinelResource注解了,继续控制台新建流控,此时再测试就会返回自定义的反悔了
{"code": 100,"msg": "接口被限流了"}
这里推荐用这种方式,对业务逻辑代码侵入较小
后台也打印出了异常的详细信息
2023-11-01 21:20:16.840 INFO 17948 --- [nio-8089-exec-2] c.s.s.order.MyBlockExceptionHandler : BlockExceptionHandler BlockException================FlowRule{resource=/order/add, limitApp=default, grade=1, count=2.0, strategy=0, refResource=null, controlBehavior=0, warmUpPeriodSec=10, maxQueueingTimeMs=500, clusterMode=false, clusterConfig=ClusterFlowConfig{flowId=null, thresholdType=0, fallbackToLocalWhenFail=true, strategy=0, sampleCount=10, windowIntervalMs=1000, resourceTimeout=2000, resourceTimeoutStrategy=0, acquireRefuseStrategy=0, clientOfflineTime=2000}, controller=com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController@39a550ee}
我们可以根据这些信息进行更加个性化的异常定制。如果需要更加特殊对某个请求进行专门定制的话,可以用回上面注解的模式!
