目錄spring
在日常項目中爲了防止一些沒有token訪問的API被大量無限的調用,須要對一些服務進行API限流。就比如拿一些註冊或者發驗證碼的一些接口,若是被惡意無限的調用,多少會形成一些費用的產生,發短信或者郵件都是一些第三方接口,次數越多,固然費用也就越多了,嚴重的直接致使服務崩潰。spring cloud api-gateway中引入限流的配置仍是必須的。api
在pom文件中引入Zuul RateLimit的依賴this
<dependency> <groupId>com.marcosbarbero.cloud</groupId> <artifactId>spring-cloud-zuul-ratelimit</artifactId> <version>1.3.2.RELEASE</version> </dependency>
更詳細的配置解讀下面有寫,這裏只是簡單配置一下,如下這個配置就能夠對服務進行限流了 zuul: routes: 你的路由配置 test: path: serviceId: ratelimit: enabled: true policies: test: 路由名 limit: 限制次數 refresh-interval: 刷新時間 type: 類型
本地讓本身的一個服務配置爲一分鐘內該服務的API只能訪問十次,超過十次,網關就會報錯url
zuul: routes: test: path: /api/test/** serviceId: hscf-cloud-test-9457 ratelimit: enabled: true policies: test: limit: 10 refresh-interval: 60 type: origin 限流方式
下面經過源碼簡要分析一下代理
RateLimit類是繼承ZuulFilter,內中的變量不難看出就是咱們在yml文件中配置的屬性值。RateLimit內中的部分源碼,filterType爲「pre」表示在每個API訪問以前進行攔截,LIMIT_HEADER,REMAINING_HEADER,RESET_HEADER這三個變量應該就是獲取咱們配置的訪問次數,還有記錄該時間內剩餘的訪問次數。code
public class RateLimitFilter extends ZuulFilter { public static final String LIMIT_HEADER = "X-RateLimit-Limit"; public static final String REMAINING_HEADER = "X-RateLimit-Remaining"; public static final String RESET_HEADER = "X-RateLimit-Reset"; public String filterType() { return "pre"; } public int filterOrder() { return -1; } public boolean shouldFilter() { return this.properties.isEnabled() && this.policy(this.route()).isPresent(); }
主體邏輯run()中進行判斷。先經過this.policy(route).ifPresent((policy)判斷policy配置信息是否存在,存在的話會讀
取到當前的限制值,還剩餘的限制值,最終判斷剩餘的限制值是否小於0,小於0的話就會報出太多請求的異常
TOO_MANY_REQUESTS(429, "Too Many Requests")繼承
public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletResponse response = ctx.getResponse(); HttpServletRequest request = ctx.getRequest(); Route route = this.route(); this.policy(route).ifPresent((policy) -> { String key = this.rateLimitKeyGenerator.key(request, route, policy); Rate rate = this.rateLimiter.consume(policy, key); response.setHeader("X-RateLimit-Limit", policy.getLimit().toString()); response.setHeader("X-RateLimit-Remaining", String.valueOf(Math.max(rate.getRemaining().longValue(), 0L))); response.setHeader("X-RateLimit-Reset", rate.getReset().toString()); if(rate.getRemaining().longValue() < 0L) { ctx.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value()); ctx.put("rateLimitExceeded", "true"); throw new ZuulRuntimeException(new ZuulException(HttpStatus.TOO_MANY_REQUESTS.toString(), HttpStatus.TOO_MANY_REQUESTS.value(), (String)null)); } }); return null; } 。。。。。。
控制檯的異常信息,異常code爲429,也就是太多請求的異常:TOO_MANY_REQUESTS(429, "Too Many Requests")token
zuul: ratelimit: key-prefix: your-prefix #對應用來標識請求的key的前綴 enabled: true repository: REDIS #對應存儲類型(用來存儲統計信息) behind-proxy: true #代理以後 default-policy: #可選 - 針對全部的路由配置的策略,除非特別配置了policies limit: 10 #可選 - 每一個刷新時間窗口對應的請求數量限制 quota: 1000 #可選- 每一個刷新時間窗口對應的請求時間限制(秒) refresh-interval: 60 # 刷新時間窗口的時間,默認值 (秒) type: #可選 限流方式 - user - origin - url policies: myServiceId: #特定的路由 limit: 10 #可選- 每一個刷新時間窗口對應的請求數量限制 quota: 1000 #可選- 每一個刷新時間窗口對應的請求時間限制(秒) refresh-interval: 60 # 刷新時間窗口的時間,默認值 (秒) type: #可選 限流方式 - user - origin - url
目前只是將網關中的限流方式使用連起來,源碼中的原理知道了一下,後續能夠繼續進行擴展,能夠針對請求上的參數進行請求攔截限流接口