微服务架构中API网关承担统一入口职责,路由转发、鉴权、限流、熔断等横切逻辑从各服务收敛到网关层。Spring Cloud Gateway基于Spring WebFlux构建,非阻塞模型吞吐表现优于Zuul等同步网关。本文给出Gateway的路由配置、动态路由加载、限流与自定义过滤器实现。
Spring Cloud Gateway路由基础配置
Gateway的核心概念是Route(路由)、Predicate(断言)和Filter(过滤器)。一条Route由ID、目标URI、断言链和过滤器链组成。断言决定请求是否匹配该路由,过滤器对请求和响应做加工。
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- Method=GET,POST
- Header=Authorization, .+
filters:
- StripPrefix=2
- AddRequestHeader=X-Gateway-Source, gateway
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=2
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200
lb://前缀表示使用服务发现(Nacos或Eureka)做负载均衡。StripPrefix=2截掉URL前两层路径,/api/users/detail转发到user-service的/detail。RequestRateLimiter配合Redis实现令牌桶限流,replenishRate为每秒令牌填充速率,burstCapacity为桶容量上限。
动态路由:不重启网关更新路由规则
静态配置每次改路由都要重启网关,生产环境不可接受。动态路由方案把路由定义存入Nacos配置中心,网关监听配置变更实时刷新:
@Configuration
public class DynamicRouteConfig {
@Autowired
private RouteDefinitionLocator routeDefinitionLocator;
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Bean
public ApplicationListener<RefreshRoutesEvent> routesRefreshListener() {
return event -> {
// Nacos配置变更时重新加载路由
routeDefinitionLocator.getRouteDefinitions()
.collectList()
.subscribe(definitions -> {
// 先清空旧路由
definitions.forEach(def ->
routeDefinitionWriter.delete(Mono.just(def.getId())));
// 写入新路由
definitions.forEach(def ->
routeDefinitionWriter.save(Mono.just(def)));
});
};
}
}
也可以用Gateway提供的Actuator端点动态增删路由,POST到/actuator/gateway/routes/{id}添加路由,DELETE删除路由,不需要重新打包部署。动态路由配合Nacos配置中心实现路由规则版本化管理,每次变更可追溯。
全局过滤器:鉴权与请求日志
全局过滤器对所有路由生效,适合做鉴权、日志、链路追踪等通用逻辑:
@Component
@Order(-100)
public class AuthGlobalFilter implements GlobalFilter {
@Autowired
private JwtUtil jwtUtil;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 白名单路径直接放行
if (path.contains("/auth/login") || path.contains("/auth/register")) {
return chain.filter(exchange);
}
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorizedResponse(exchange, "缺少认证令牌");
}
try {
String jwt = token.substring(7);
Claims claims = jwtUtil.parseToken(jwt);
// 将用户信息透传到下游服务
ServerHttpRequest mutated = request.mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Role", claims.get("role", String.class))
.build();
return chain.filter(exchange.mutate().request(mutated).build());
} catch (Exception e) {
return unauthorizedResponse(exchange, "令牌无效或已过期");
}
}
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
String body = "{\"code\":401,\"message\":\"" + msg + "\"}";
DataBuffer buffer = response.bufferFactory()
.wrap(body.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(buffer));
}
}
鉴权过滤器在路由过滤器之前执行(@Order(-100)),验证JWT后将用户ID和角色透传到下游服务的请求头中。下游服务从Header中取用户信息,不需要重复验签。
熔断降级与重试策略
Gateway集成Resilience4j实现熔断降级,下游服务异常时返回兜底响应:
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- name: CircuitBreaker
args:
name: orderCircuitBreaker
fallbackUri: forward:/fallback/order
resilience4j:
circuitbreaker:
instances:
orderCircuitBreaker:
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3
失败率达到50%时熔断器打开,后续请求直接走fallbackUri返回降级响应。10秒后进入半开状态,放行3个探测请求,全部成功则恢复,否则继续熔断。配合Retry过滤器对可重试异常(如超时)做自动重试,但幂等性要求高的接口要限制重试次数,避免重复扣款。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-wang-guan-shi-zhan-dong-tai-lu-you-yu/