1. GatewayFilter
GatewayFilter
is a simple interface used to define the behavior of a gateway filter. A gateway filter is a class that implements the GatewayFilter
interface and can perform certain operations when a request enters the gateway or when a response leaves the gateway. Filters can be used to modify requests or responses, log, add headers, and more.
public interface GatewayFilter { Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); }
A simple custom gateway filter,:
public class MyFilter implements GatewayFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getAttributes().put("start",System.currentTimeMillis()); return chain.filter(exchange).then(Mono.fromRunnable(new Runnable() { @Override public void run() { long start = exchange.getAttribute("start"); System.out.println(exchange.getRequest().getURI() + "Execution time:" + (System.currentTimeMillis()-start)); } })); } @Override public int getOrder() { return 0; } }
Configuration:
@Configuration public class MyConfig { /**Configure custom filters*/ @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes().route(r -> r.path("/provider/**")//The path visited by the user .uri("lb://service-provider")//The real server ip + port of the route .filters(new MyFilter()) // Local filter .id("provider_route")) // Route id .build(); } }
2. AbstractGatewayFilterFactory
AbstractGatewayFilterFactory
is an abstract class used to create gateway filters more conveniently. It handles filter parameter parsing and creation, making defining filters much simpler.
public class MyCustomGatewayFilterFactory extends AbstractGatewayFilterFactory<MyCustomGatewayFilterFactory.Config> { public MyCustomGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config, Class<Config> configClass) { //Create and return filter instance here return (exchange, chain) -> { // filter logic return chain.filter(exchange); }; } public static class Config { //Filter configuration parameters } }
The following is a simple current limit implemented through the token bucket algorithm:
import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.stereotype.Component; @Component public class RateLimitByIpGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimitByIpGatewayFilterFactory.Config> { public RateLimitByIpGatewayFilterFactory() { super(Config.class); } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { // Get the requested IP address String ipAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); // Use simple IP-based current limiting logic, you can choose other current limiting algorithms according to actual needs // Here we use a simple token bucket algorithm as an example if (isRateLimited(ipAddress, config.getLimit())) { //If the current limit threshold is exceeded, return an error response exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS); return exchange.getResponse().setComplete(); } // If the current limit threshold is not exceeded, continue processing the request return chain.filter(exchange); }; } private boolean isRateLimited(String ipAddress, int limit) { //Implement your current limiting logic here, using a simple token bucket algorithm as an example // You can use a library such as Google Guava RateLimiter to simplify the implementation // This is just a simple example, please make more complex implementations based on actual needs. // In a real scenario, you may need to record the access frequency to the database or distributed cache //A simple Map is used here to simulate the storage token bucket. Map<String, Long> tokenBucket = new ConcurrentHashMap<>(); // Get the current timestamp long now = System.currentTimeMillis(); // Get or initialize the token bucket tokenBucket.putIfAbsent(ipAddress, now); // Get the last access time long lastAccessTime = tokenBucket.get(ipAddress); // Calculate time interval long interval = now - lastAccessTime; // Calculate token generation rate double rate = 1000.0 / limit; // Assume a limit on the number of requests per second // Calculate the number of tokens that should be generated int tokensToAdd = (int) (interval / rate); //Update the number of tokens in the token bucket tokenBucket.put(ipAddress, now + tokensToAdd); // Check if the number of tokens exceeds the threshold return tokensToAdd > limit; } public static class Config { private int limit; public int getLimit() { return limit; } public void setLimit(int limit) { this.limit = limit; } } }
Configuration file configuration current limiting threshold:
spring: cloud: gateway: routes: - id: rate_limit_route uri: http://example.com filters: - RateLimitByIp=1 predicates: - Path=/api/**
The above configuration will limit requests under the /api/**
path to 1 request per second. Please note that RateLimitByIp
needs to be in the same case as the class name of RateLimitByIpGatewayFilterFactory
, and the parameter 1
is used to set the current limit threshold. You Can be adjusted as needed.
Fixed-capacity token bucket: There is a fixed number of tokens in the token bucket, and these tokens are added to the bucket at a fixed rate.
Token Add Rate: Tokens are added to the token bucket at a constant rate (e.g. a fixed number of tokens per second).
Token consumption: When a request arrives, a token needs to be obtained from the token bucket. If there are enough tokens in the token bucket, the request is allowed to be processed and one token is consumed; otherwise, the request is throttled.
Smooth current limiting: Since tokens are added at a constant rate, the token bucket algorithm can achieve smooth current limiting, that is, requests are processed evenly instead of being rejected suddenly.
Adapt to burst traffic: The token bucket algorithm is also adaptable to handle burst traffic, because even if the token bucket is empty for a period of time, once a token is added, it can handle new ones. ask.
Good fault tolerance: Since the token bucket algorithm is time-based, it has good fault tolerance for time-sensitive applications. And since each request requires a token from the token bucket, the impact of burst requests on the system can be effectively prevented.
3. Difference
-
Designed:
- GatewayFilter: It is a simple interface used to define the behavior of gateway filters. The implementation of each filter needs to directly implement the methods in the
GatewayFilter
interface. - AbstractGatewayFilterFactory: is an abstract class designed to make it easier to create gateway filters with configuration parameters. By inheriting this abstract class, you can more easily handle the parsing of configuration parameters and the creation of filter instances.
-
Usage:
- GatewayFilter: Directly implement the
GatewayFilter
interface and write filter logic. This approach is suitable for simple filters that do not require configuration parameters. - AbstractGatewayFilterFactory: Inherit this abstract class, implement the abstract methods
apply
andapply(C config, Class
, and process the configuration there parameters and create a filter instance. This method is suitable for filters that require configuration parameters.configClass)
-
Configuration parameters:
- GatewayFilter: If the filter requires configuration parameters, the parameters need to be passed through other methods (such as constructors, property injection, etc.) because the
GatewayFilter
interface itself does not provide a direct configuration mechanism. - AbstractGatewayFilterFactory: Specify the type of configuration parameters through the generic parameter
C
and receive the configuration parameters in theapply
method. This allows for more flexible handling of configuration parameters, and Spring Cloud Gateway will be responsible for binding the configuration parameters to the filter instance.