您好,登錄后才能下訂單哦!
Spring Cloud Netflix Zuul是一個包含Netflix Zuul的 開源網關。它為Spring Boot應用程序添加了一些特定功能。不幸的是,開箱即用不提供速率限制。
除了Spring Cloud Netflix Zuul依賴項之外,我們還需要將Spring Cloud Zuul RateLimit 添加到我們的應用程序的pom.xml中:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>com.marcosbarbero.cloud</groupId> <artifactId>spring-cloud-zuul-ratelimit</artifactId> <version>2.2.0.RELEASE</version> </dependency>
首先,讓我們創建幾個REST端點,我們將在其上應用速率限制。
下面是一個簡單的Spring Controller類,有兩個端點:
@Controller @RequestMapping("/greeting") public class GreetingController { @GetMapping("/simple") public ResponseEntity<String> getSimple() { return ResponseEntity.ok("Hi!"); } @GetMapping("/advanced") public ResponseEntity<String> getAdvanced() { return ResponseEntity.ok("Hello, how you doing?"); } }
讓我們在application.yml文件中添加以下Zuul屬性 :
zuul: routes: serviceSimple: path: /greeting/simple url: forward:/ serviceAdvanced: path: /greeting/advanced url: forward:/ ratelimit: enabled: true repository: JPA policy-list: serviceSimple: - limit: 5 refresh-interval: 60 type: - origin serviceAdvanced: - limit: 1 refresh-interval: 2 type: - origin strip-prefix: true
在zuul.routes下,我們提供端點詳細信息。在zuul.ratelimit.policy-list下,我們為端點提供速率限制配置。該限屬性指定的時間端點可以在內部被稱為數字刷新間隔。
我們可以看到,我們為serviceSimple 端點添加了每60秒5個請求的速率限制。相比之下, serviceAdvanced的速率限制為每2秒1個請求。
該類型配置指定其速率限制的方法,以下是可能的值:
接下來,讓我們測試一下速率限制:
@Test public void whenRequestNotExceedingCapacity_thenReturnOkResponse() { ResponseEntity<String> response = restTemplate.getForEntity(SIMPLE_GREETING, String.class); assertEquals(OK, response.getStatusCode()); HttpHeaders headers = response.getHeaders(); String key = "rate-limit-application_serviceSimple_127.0.0.1"; assertEquals("5", headers.getFirst(HEADER_LIMIT + key)); assertEquals("4", headers.getFirst(HEADER_REMAINING + key)); assertEquals("60000", headers.getFirst(HEADER_RESET + key)); }
在這里,我們只對一個端點/ greeting / simple進行一次調用。請求成功,因為它在速率限制內。
另一個關鍵點是,對于每個響應,我們返回標頭Header,為我們提供有關速率限制的更多信息。對于上述請求,我們將獲得以下標頭:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5 X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 4 X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 60000
解釋:
另外,如果我們再次立即觸發相同的端點,我們可以得到:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1: 5 X-RateLimit-Remaining-rate-limit-application_serviceSimple_127.0.0.1: 3 X-RateLimit-Reset-rate-limit-application_serviceSimple_127.0.0.1: 57031
請注意減少的剩余嘗試次數和剩余的毫秒數。
讓我們看看當我們超過速率限制時會發生什么:
@Test public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException { ResponseEntity<String> response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); assertEquals(OK, response.getStatusCode()); for (int i = 0; i < 2; i++) { response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); } assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); HttpHeaders headers = response.getHeaders(); String key = "rate-limit-application_serviceAdvanced_127.0.0.1"; assertEquals("1", headers.getFirst(HEADER_LIMIT + key)); assertEquals("0", headers.getFirst(HEADER_REMAINING + key)); assertNotEquals("2000", headers.getFirst(HEADER_RESET + key)); TimeUnit.SECONDS.sleep(2); response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); assertEquals(OK, response.getStatusCode()); }
在這里,我們快速連續兩次調用,由于我們已將速率限制配置為每2秒一個請求,因此第二個調用將失敗。結果,錯誤代碼429(Too Many Requests)返回給客戶端。以下是達到速率限制時返回的標頭:
X-RateLimit-Limit-rate-limit-application_serviceAdvanced_127.0.0.1: 1 X-RateLimit-Remaining-rate-limit-application_serviceAdvanced_127.0.0.1: 0 X-RateLimit-Reset-rate-limit-application_serviceAdvanced_127.0.0.1: 268
之后,我們休息了2秒鐘。這是為端點配置的刷新間隔。最后,我們再次觸發端點并獲得成功的響應。
自定義密鑰生成器
我們可以使用自定義密鑰生成器自定義響應頭中發送的密鑰。這很有用,因為應用程序可能需要控制除type屬性提供的選項之外的密鑰策略。
例如,這可以通過創建自定義的RateLimitKeyGenerator實現類來完成。我們可以添加更多的限定符或完全不同的東西:
@Bean public RateLimitKeyGenerator rateLimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) { return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) { @Override public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) { return super.key(request, route, policy) + "_" + request.getMethod(); } }; }
上面的代碼將REST方法名稱附加到鍵。例如:
X-RateLimit-Limit-rate-limit-application_serviceSimple_127.0.0.1_GET: 5
另一個關鍵點是 RateLimitKeyGenerator bean將由spring-cloud-zuul-ratelimit自動配置。
自定義錯誤處理
該框架支持速率限制數據存儲的各種實現。例如,提供了Spring Data JPA和Redis。默認情況下,使用DefaultRateLimiterErrorHandler 類將故障記錄為錯誤。
當我們需要以不同方式處理錯誤時,我們可以定義一個自定義的RateLimiterErrorHandler bean:
@Bean public RateLimiterErrorHandler rateLimitErrorHandler() { return new DefaultRateLimiterErrorHandler() { @Override public void handleSaveError(String key, Exception e) { <i>// implementation</i> } @Override public void handleFetchError(String key, Exception e) { <i>// implementation</i> } @Override public void handleError(String msg, Exception e) { <i>// implementation</i> } }; }
與RateLimitKeyGenerator bean 類似 ,也將自動配置RateLimiterErrorHandler bean。
在GitHub上 找到本文的完整代碼
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。