1. 引言Spring Cloud Gateway 是 Spring Cloud 生态中基于 Spring WebFlux 和 Project Reactor 构建的 API 网关。它提供了动态路由、限流、熔断、安全认证等核心功能是现代微服务架构中不可或缺的组件。本文将围绕三个核心主题展开路由配置、基于 Redis 的限流RedisRateLimiter以及JWT 认证与授权过滤器的实现并提供完整的代码示例。2. 环境与依赖准备首先创建一个 Spring Boot 项目并添加以下核心依赖以 Maven 为例dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis-reactive/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/version scoperuntime/scope /dependency /code确保你的application.yml中配置了 Redis 连接信息spring: redis: host: localhost port: 6379 password: database: 03. 路由配置Spring Cloud Gateway 支持两种路由配置方式基于配置文件的静态路由和基于代码的动态路由。3.1 静态路由配置YAML在application.yml中定义路由规则spring: cloud: gateway: routes: - id: user-service-route uri: lb://USER-SERVICE predicates: - Path/api/users/** filters: - StripPrefix1 - id: order-service-route uri: lb://ORDER-SERVICE predicates: - Path/api/orders/** filters: - StripPrefix1 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 key-resolver: #{userKeyResolver}解释id路由唯一标识。uri目标服务地址lb://表示通过服务发现如 Nacos、Eureka进行负载均衡。predicates断言条件Path表示路径匹配。filters网关过滤器链StripPrefix1表示去掉路径前缀的第一段例如/api/users/info转发到用户服务时变为/info。3.2 动态路由配置Java Config通过Configuration类定义路由import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class GatewayRouteConfig { Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route(product-service, r - r .path(/api/products/**) .filters(f - f.stripPrefix(1) .addRequestHeader(X-Gateway-Source, SpringCloudGateway)) .uri(lb://PRODUCT-SERVICE)) .route(auth-service, r - r .path(/auth/**) .uri(lb://AUTH-SERVICE)) .build(); } }4. 基于 Redis 的限流RedisRateLimiterSpring Cloud Gateway 内置了RequestRateLimiter过滤器可与 Redis 配合实现分布式限流。4.1 配置限流过滤器在路由配置中启用限流并指定 key 解析器filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒允许的请求数令牌桶填充速率 redis-rate-limiter.burstCapacity: 20 # 令牌桶容量瞬时最大并发 key-resolver: #{userKeyResolver} # 限流键解析器 Bean 名称4.2 实现 KeyResolver限流键决定了如何区分用户或客户端。常见方式包括按用户 ID、IP 或 API 路径限流。import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; Configuration public class RateLimitConfig { // 按请求 IP 限流 Bean public KeyResolver ipKeyResolver() { return exchange - Mono.just( exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() ); } // 按用户 ID 限流需从 JWT 或 Session 中提取 Bean public KeyResolver userKeyResolver() { return exchange - { // 假设从请求头中获取用户 ID String userId exchange.getRequest().getHeaders().getFirst(X-User-Id); if (userId null || userId.isEmpty()) { userId anonymous; } return Mono.just(userId); }; } // 按 API 路径限流 Bean public KeyResolver apiKeyResolver() { return exchange - Mono.just( exchange.getRequest().getPath().value() ); } }然后在application.yml中引用对应的 Bean例如key-resolver: #{ipKeyResolver}。4.3 限流响应自定义当请求被限流时默认返回 HTTP 429 Too Many Requests。你可以通过自定义异常处理器来返回更友好的响应import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; import org.springframework.cloud.gateway.support.NotFoundException; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; Order(-1) Configuration public class GlobalExceptionHandler implements ErrorWebExceptionHandler { Override public Monolt;Voidgt; handle(ServerWebExchange exchange, Throwable ex) { ServerHttpResponse response exchange.getResponse(); if (response.isCommitted()) { return Mono.error(ex); } // 处理限流异常 if (ex instanceof ResponseStatusException amp;amp;amp;amp; ((ResponseStatusException) ex).getStatus() HttpStatus.TOO_MANY_REQUESTS) { response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); String body {\code\:429,\message\:\请求过于频繁请稍后再试\}; DataBuffer buffer response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8)); return response.writeWith(Mono.just(buffer)); } // 其他异常处理... response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); return response.setComplete(); } }5. JWT 认证与授权过滤器在微服务网关中通常由网关统一进行 JWT 令牌的验证和用户信息的提取然后将用户信息传递给下游服务。5.1 JWT 工具类首先创建一个 JWT 工具类用于生成和解析令牌import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; Component public class JwtUtil { Value(${jwt.secret:defaultSecretKey}) private String secret; Value(${jwt.expiration:3600000}) private Long expiration; // 毫秒 private Key key; PostConstruct public void init() { this.key Keys.hmacShaKeyFor(secret.getBytes()); } // 生成令牌 public String generateToken(String username, Maplt;String, Objectgt; claims) { return Jwts.builder() .setClaims(claims) .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() expiration)) .signWith(key, SignatureAlgorithm.HS256) .compact(); } // 解析令牌 public Claims parseToken(String token) { return Jwts.parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); } // 验证令牌 public boolean validateToken(String token) { try { parseToken(token); return true; } catch (Exception e) { return false; } } }5.2 认证过滤器GlobalFilter实现一个全局过滤器对需要认证的路径进行 JWT 校验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.List; Component public class JwtAuthenticationFilter implements GlobalFilter, Ordered { private final JwtUtil jwtUtil; // 白名单路径无需认证 private static final Listlt;Stringgt; WHITE_LIST List.of( /auth/login, /auth/register, /public/** ); public JwtAuthenticationFilter(JwtUtil jwtUtil) { this.jwtUtil jwtUtil; } Override public Monolt;Voidgt; filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path exchange.getRequest().getPath().value(); // 检查是否为白名单路径 if (WHITE_LIST.stream().anyMatch(path::startsWith)) { return chain.filter(exchange); } // 从请求头获取令牌 String token exchange.getRequest().getHeaders().getFirst(Authorization); if (token null || !token.startsWith(Bearer )) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } token token.substring(7); // 去掉 Bearer 前缀 // 验证令牌 if (!jwtUtil.validateToken(token)) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 解析用户信息并传递给下游服务 try { Claims claims jwtUtil.parseToken(token); String username claims.getSubject(); // 将用户信息添加到请求头中 exchange exchange.mutate() .request(builder -gt; builder.header(X-User-Name, username)) .build(); } catch (Exception e) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; // 高优先级最先执行 } }5.3 授权过滤器自定义 GatewayFilter对于需要特定角色或权限的接口可以创建自定义的 GatewayFilterimport 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.Arrays; import java.util.List; Component public class RoleAuthorizationGatewayFilterFactory extends AbstractGatewayFilterFactoryRoleAuthorizationGatewayFilterFactory.Config { public RoleAuthorizationGatewayFilterFactory() { super(Config.class); } Override public GatewayFilter apply(Config config) { return (exchange, chain) - { String requiredRole config.getRequiredRole(); // 从请求头获取用户角色实际应从 JWT 解析 String userRole exchange.getRequest().getHeaders().getFirst(X-User-Role); if (userRole null || !userRole.equals(requiredRole)) { exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); return exchange.getResponse().setComplete(); } return chain.filter(exchange); }; } Override public Listlt;Stringgt; shortcutFieldOrder() { return Arrays.asList(requiredRole); } public static class Config { private String requiredRole; public String getRequiredRole() { return requiredRole; } public void setRequiredRole(String requiredRole) { this.requiredRole requiredRole; } } }在路由配置中使用该过滤器spring: cloud: gateway: routes: - id: admin-route uri: lb://ADMIN-SERVICE predicates: - Path/api/admin/** filters: - StripPrefix1 - name: RoleAuthorization args: requiredRole: ADMIN6. 完整配置示例与测试6.1 完整的 application.ymlserver: port: 8080 spring: application: name: api-gateway redis: host: localhost port: 6379 cloud: gateway: routes: - id: user-service uri: lb://USER-SERVICE predicates: - Path/api/users/** filters: - StripPrefix1 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 key-resolver: #{ipKeyResolver} - id: auth-service uri: lb://AUTH-SERVICE predicates: - Path/auth/** filters: - StripPrefix0 - id: admin-service uri: lb://ADMIN-SERVICE predicates: - Path/api/admin/** filters: - StripPrefix1 - name: RoleAuthorization args: requiredRole: ADMIN jwt: secret: mySuperSecretKeyForJwtSigning123! expiration: 36000006.2 测试步骤启动 Redis 服务。启动网关应用。使用 Postman 或 curl 测试认证测试访问/api/users/1不带 Token应返回 401。限流测试快速连续请求/api/users/1带有效 Token超过 10 次/秒后应返回 429。授权测试访问/api/admin/dashboard带普通用户 Token应返回 403带 ADMIN 角色 Token 应成功。7. 总结本文详细介绍了 Spring Cloud Gateway 的三个核心功能