RateLimiter 過濾器
RateLimiter 過濾器使用 Bucket4j 來確定當前請求是否允許繼續。如果不允許,則返回 HTTP 429 - Too Many Requests(預設)狀態。
在閱讀本文件之前,請查閱 Bucket4j 概念。
Bucket4j 使用的演算法是 令牌桶演算法。
過濾器接受 keyResolver 引數和其他 Bucket4j 配置引數。鍵解析器是一個 java.util.Function<ServerRequest, String>。這允許使用者從請求中提取任何資訊作為配置的 Bucket4j 分散式 機制中的鍵。常見的鍵可以是 ServerRequest 中檢索到的 Principal。
預設情況下,如果鍵解析器沒有找到鍵,則請求將被 FORBIDDEN 狀態拒絕。
| 目前,配置鍵解析器的唯一方法是透過 Java DSL,而不是透過外部屬性。 |
Bucket4j 分散式配置
型別為 io.github.bucket4j.distributed.proxy.AsyncProxyManager 的 bean。為此,請使用 ProxyManager.asAsync() 方法。
import com.github.benmanes.caffeine.cache.Caffeine;
import io.github.bucket4j.caffeine.CaffeineProxyManager;
@Configuration
class RateLimiterConfiguration {
@Bean
public AsyncProxyManager<String> caffeineProxyManager() {
Caffeine<String, RemoteBucketState> builder = (Caffeine) Caffeine.newBuilder().maximumSize(100);
return new CaffeineProxyManager<>(builder, Duration.ofMinutes(1)).asAsync();
}
}
以上配置了一個使用 Caffeine 的 AsyncProxyManager,它是一個本地記憶體快取,對測試很有用。
配置桶
預設情況下,桶是使用配置的 capacity 和 period 進行配置的。容量是桶中令牌的數量。週期是一個 java.util.Duration,它定義了桶中可用令牌的重新生成時間。
其他配置項包括請求被拒絕時返回的 statusCode。預設值為 429,TO_MANY_REQUESTS。tokens 項定義了每個請求使用的令牌數量,預設為 1。headerName 項是包含剩餘令牌數量的請求頭的名稱,預設為 X-RateLimit-Remaining。timeout 選項定義了分散式桶返回響應的 Duration,預設未設定。
以下是配置帶限流的路由的示例
import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri;
import static org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.rateLimit;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
@Configuration
class RouteConfiguration {
@Bean
public RouterFunction<ServerResponse> gatewayRouterFunctionsRateLimited() {
return route("rate_limited_route")
.GET("/api/**", http())
.before(uri("https://example.org"))
.filter(rateLimit(c -> c.setCapacity(100)
.setPeriod(Duration.ofMinutes(1))
.setKeyResolver(request -> request.servletRequest().getUserPrincipal().getName())))
.build();
}
}
這配置了每分鐘 100 個令牌的桶容量的限流。鍵解析器從 Servlet 請求中獲取主體名稱。