RateLimiter Filter
RateLimiter Filter 使用 Bucket4j 确定是允许当前请求继续进行。如果不是,则返回状态 HTTP 429 - Too Many Requests
(默认)。
The RateLimiter Filter use Bucket4j to determine if the current request is allowed to proceed. If it is not, a status of HTTP 429 - Too Many Requests
(by default) is returned.
在阅读本文档之前,请先查看 Bucket4j Concepts。
Please review Bucket4j Concepts prior to reading this documentation.
Bucket4j 使用的算法是 Token Bucket Algorithm。
The algorithm used by Bucket4j is the Token Bucket Algorithm.
该过滤器采用 keyResolver
参数和其他 Bucket4j 配置参数。键解析器是 java.util.Function<ServerRequest, String>
。这使用户能够从请求中提取任何信息,以用作在已配置的 Bucket4j distribution 机制中作为键。一个常见的键将是从 ServerRequest
检索到的 Principal
。
The filter takes a keyResolver
parameter and other Bucket4j configuration parameters. The key resolver is a java.util.Function<ServerRequest, String>
. This allows the user to extract any information out of the request to use as a key in the configured Bucket4j distribution mechanism. A common key would be the Principal
retrieved from the ServerRequest
.
默认情况下,如果关键解析器找不到键,那么将会以 FORBIDDEN
状态拒绝请求。
By default, if the key resolver does not find a key, requests are denied with the FORBIDDEN
status.
当前,配置键解析器的唯一方法是通过 Java DSL 而不是通过外部属性。 |
Currently, the only way to configure key resolvers is through the Java DSL and not through external properties. |
Bucket4j Distributed Configuration
一个 io.github.bucket4j.distributed.proxy.AsyncProxyManager
类型的 bean。要执行此操作,请使用 ProxyManager.asAsync()
方法。
A bean of type io.github.bucket4j.distributed.proxy.AsyncProxyManager
. To do this, use the ProxyManager.asAsync()
method.
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
,对于测试非常有用。
The above configures an AsyncProxyManager
using Caffeine
, a local in-memory cache, useful for testing.
Configuring Buckets
默认情况下,Bucket 会使用已配置的 “capacity” 和 “period” 进行配置。容量是指 Bucket 中有多少个令牌。period 是一个 java.util.Duration
,它定义了 Bucket 中可用的令牌重新生成的时长。
By default, the Bucket is configured using a configured capacity
and period
. Capacity is how many tokens the bucket has. The period is a java.util.Duration
that defines how long for the tokens available in the bucket to be regenerated.
其他配置项是请求被拒绝时返回的 statusCode
。默认情况下它为 429,即 TO_MANY_REQUESTS。tokens
项定义每个请求使用了多少令牌,默认值为 1。headerName
项是包含剩余令牌数的标头的名称,默认为 X-RateLimit-Remaining
。timeout
选项为分布式 Bucket 返回答案定义一个 Duration
,默认情况下不会设置。
Other configuration items are the statusCode
returned when the request is denied. By default it is 429, TO_MANY_REQUESTS. The tokens
item defines how many tokens are used for each request and defaults to 1. The headerName
item is the name of the header that contains the number of remaining tokens, this defaults to X-RateLimit-Remaining
. The timeout
option defines a Duration
for the distributed bucket to return an answer and is not set by default.
下面是一个为路由配置限流的示例:
The following is an example of configuring a route with rate limiting:
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("https://example.org"))
.filter(rateLimit(c -> c.setCapacity(100)
.setPeriod(Duration.ofMinutes(1))
.setKeyResolver(request -> request.servletRequest().getUserPrincipal().getName())))
.build();
}
}
这将使用每分钟 100 个令牌的 Bucket 容量来配置限流。密钥解析器从 Servlet 请求中获取主体名称。
This configures the rate limiting with a bucket capacity of 100 tokens per minute. The key resolver gets the principle name from the Servlet request.