前面我們講解了Sentinel整合Spring Cloud Gateway,詳細請查看文章:阿里Sentinel支持Spring Cloud Gateway啦
目前來說,大部分公司線上的網關應該是Zuul,所以今天我們就來看看如何在Zuul中整合Sentinel。本來想基於Spring Cloud Alibaba來進行整合講解,整合的時候發現目前還沒更新版本,依賴還是之前的版本,咱們就以最原生的方式進行整合吧,等Spring Cloud Alibaba更新之后,Sentinel的整合只會變得更簡單。
加入zuul-adapter依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
<version>1.6.0</version>
</dependency>
配置Sentinel提供的限流過濾器和限流規則:
@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);
}
}
- SentinelZuulPreFilter
pre過濾器,在請求路由之前匹配routeId和api,進行限流操作 - SentinelZuulPostFilter
post過濾器,路由之后恢復資源 - SentinelZuulErrorFilter
error過濾器,異常后的處理
最后再配置一個簡單的路由,路由名稱yinjihuan,跟上面規則中的名稱一致:
zuul.routes.yinjihuan.path=/cxytiandi/**
zuul.routes.yinjihuan.url=http://cxytiandi.com
觸發限流后會返回固定的提示:
{
"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