阿里Sentinel整合Zuul閘道器詳解
前面我們講解了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
歡迎加入我的知識星球,一起交流技術,免費學習猿天地的課程( http://cxytiandi.com/course )
PS:目前星球中正在星主的帶領下組隊學習Spring Cloud,等你哦!