我们在八、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;
@Component
public 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}
我们可以根据这些信息进行更加个性化的异常定制。如果需要更加特殊对某个请求进行专门定制的话,可以用回上面注解的模式!