Spring Cloud Gateway实现API访问频率限制
在微服务架构中,API网关扮演着至关重要的角色,它不仅负责路由请求,还能提供诸如安全性、监控和限流等功能。Spring Cloud Gateway作为Spring Cloud生态系统中的一员,提供了强大的路由和过滤功能。本文将详细介绍如何使用Spring Cloud Gateway的全局过滤器(Global Filters)或特定路由的过滤器(Gateway Filters)来实现对外部接口的访问频率限制。
一、为什么需要访问频率限制?
访问频率限制(Rate Limiting)是保护后端服务免受恶意或异常流量攻击的重要手段。通过限制客户端在一定时间窗口内的请求次数,可以有效防止服务过载,保障系统的稳定性和可用性。
二、使用全局过滤器实现访问频率限制
全局过滤器适用于对所有路由进行统一的访问频率限制。以下是实现这一功能的详细步骤和示例代码。
步骤:
-
创建一个自定义的全局过滤器: 实现
GlobalFilter
接口,并在过滤器中实现访问频率限制逻辑。 -
配置过滤器: 将自定义的全局过滤器注册到Spring Cloud Gateway中。
示例代码:
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class RateLimitGlobalFilter implements GlobalFilter, Ordered {
private final ConcurrentHashMap<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String ipAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
AtomicInteger count = requestCounts.computeIfAbsent(ipAddress, k -> new AtomicInteger(0));
if (count.incrementAndGet() > 10) { // 每秒最多10次请求
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if (count.decrementAndGet() == 0) {
requestCounts.remove(ipAddress);
}
}));
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
三、使用特定路由的过滤器实现访问频率限制
特定路由的过滤器适用于对特定路由进行访问频率限制。
步骤:
-
创建一个自定义的GatewayFilter工厂: 实现
GatewayFilterFactory
接口,并在工厂中实现访问频率限制逻辑。 -
配置路由过滤器: 在路由配置中使用自定义的GatewayFilter工厂。
示例代码:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class RateLimitGatewayFilterFactory extends AbstractGatewayFilterFactory<RateLimitGatewayFilterFactory.Config> {
private final ConcurrentHashMap<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();
public RateLimitGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String routeId = exchange.getRequest().getPath().toString();
AtomicInteger count = requestCounts.computeIfAbsent(routeId, k -> new AtomicInteger(0));
if (count.incrementAndGet() > config.getMaxRequestsPerSecond()) { // 每秒最多config.getMaxRequestsPerSecond()次请求
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if (count.decrementAndGet() == 0) {
requestCounts.remove(routeId);
}
}));
};
}
public static class Config {
private int maxRequestsPerSecond;
public int getMaxRequestsPerSecond() {
return maxRequestsPerSecond;
}
public void setMaxRequestsPerSecond(int maxRequestsPerSecond) {
this.maxRequestsPerSecond = maxRequestsPerSecond;
}
}
}
在application.yml
中配置路由过滤器:
cloud:
gateway:
routes:
- id: rate_limited_route
uri: http://example.com
predicates:
- Path=/rate_limited_path
filters:
- name: RateLimit
args:
maxRequestsPerSecond: 10
四、总结
通过以上步骤和示例代码,可以在Spring Cloud Gateway中实现对外部接口的访问频率限制。根据具体需求选择使用全局过滤器或特定路由的过滤器,可以有效保护后端服务免受异常流量攻击,提升系统的稳定性和可用性。