前面咱们讲解了Sentinel整合Spring Cloud Gateway,详细请查看文章:阿里Sentinel支持Spring Cloud Gateway啦git
目前来讲,大部分公司线上的网关应该是Zuul,因此今天咱们就来看看如何在Zuul中整合Sentinel。原本想基于Spring Cloud Alibaba来进行整合讲解,整合的时候发现目前还没更新版本,依赖仍是以前的版本,我们就以最原生的方式进行整合吧,等Spring Cloud Alibaba更新以后,Sentinel的整合只会变得更简单。github
加入zuul-adapter依赖:json
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-zuul-adapter</artifactId> <version>1.6.0</version> </dependency>
配置Sentinel提供的限流过滤器和限流规则:api
@Configuration public class ZuulConfig { @Bean public ZuulFilter sentinelZuulPreFilter() { return new SentinelZuulPreFilter(); } @Bean public ZuulFilter sentinelZuulPostFilter() { return new SentinelZuulPostFilter(); } @Bean public ZuulFilter sentinelZuulErrorFilter() { return new SentinelZuulErrorFilter(); } @PostConstruct public void doInit() { // 注册 FallbackProvider ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider()); initGatewayRules(); } /** * 配置限流规则 */ private void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); rules.add(new GatewayFlowRule("yinjihuan").setCount(1) // 限流阈值 .setIntervalSec(1) // 统计时间窗口,单位是秒,默认是 1 秒 ); GatewayRuleManager.loadRules(rules); } }
pre过滤器,在请求路由以前匹配routeId和api,进行限流操做微信
post过滤器,路由以后恢复资源app
error过滤器,异常后的处理框架
最后再配置一个简单的路由,路由名称yinjihuan,跟上面规则中的名称一致:ide
zuul.routes.yinjihuan.path=/cxytiandi/** zuul.routes.yinjihuan.url=http://cxytiandi.com
触发限流后会返回固定的提示:post
{ "code":429, "message":"Sentinel block exception", "route":"yinjihuan" }
若是想修改提示内容能够本身实现ZuulBlockFallbackProvider接口,框架默认提供的实现是DefaultBlockFallbackProvider,源码以下:学习
public class DefaultBlockFallbackProvider implements ZuulBlockFallbackProvider { @Override public String getRoute() { return "*"; } @Override public BlockResponse fallbackResponse(String route, Throwable cause) { if (cause instanceof BlockException) { return new BlockResponse(429, "Sentinel block exception", route); } else { return new BlockResponse(500, "System Error", route); } } }
用法其实跟Zuul中的FallbackProvider一致,可是FallbackProvider比较好的是返回的ClientHttpResponse,咱们能够自定义响应内容。
Sentinel提供的ZuulBlockFallbackProvider接口中定义的返回对象是BlockResponse ,也就意味着限制了响应的字段,BlockResponse中有code,message,route三个字段,若是我想返回status, msg这两个字段目前我没找到其它的方式,不知道后续会不会支持,其实最好的是也返回ClientHttpResponse,这样就能够自定义响应内容了。
这边有个小插曲,就是咱们自定义fallbackResponse的时候若是用中文message的话,响应内容是乱码,以下:
{ code: 429, message: "??????", route: "yinjihuan" }
我看了下SentinelZuulPreFilter中的代码,以下:
这边是构造了BlockResponse,而后设置到ResponseBody中,可是没有进行编码设置,我本身改了下源码,加了一行代码:
ctx.getResponse().setContentType("application/json; charset=utf-8");
加了上面的代码后,中文就不会乱码了,效果以下:
{ code: 429, message: "访问太频繁啦", route: "yinjihuan" }
不说了,我仍是去提个issues吧: https://github.com/alibaba/Sentinel/issues/733