Spring Cloud Gateway 核心原理与实战 ⭐⭐⭐

面试题:Spring Cloud Gateway 是如何工作的?

核心回答

Spring Cloud Gateway 是 Spring Cloud 生态系统的 API 网关,基于 Spring 5、Spring Boot 2 和 Project Reactor 构建。它通过路由、断言、过滤器三个核心概念,实现了请求转发、负载均衡、限流熔断、安全认证等功能。

一、Gateway vs Zuul 对比

1.1 架构差异

┌─────────────────────────────────────────────────────────────┐
│                    Zuul 1.x 架构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  HTTP Request                                               │
│      ↓                                                      │
│  Zuul Servlet (阻塞式)                                       │
│      ↓                                                      │
│  Zuul Filter Chain                                          │
│  ├── Pre Filters                                            │
│  ├── Route Filters                                          │
│  ├── Post Filters                                           │
│  └── Error Filters                                          │
│      ↓                                                      │
│  后端服务 (同步调用)                                          │
│      ↓                                                      │
│  HTTP Response                                              │
│                                                             │
│  特点:基于 Servlet,阻塞式 IO,线程池模型                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                Spring Cloud Gateway 架构                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  HTTP Request                                               │
│      ↓                                                      │
│  Reactor Netty (非阻塞)                                      │
│      ↓                                                      │
│  DispatcherHandler                                          │
│      ↓                                                      │
│  RoutePredicateHandlerMapping                               │
│      ↓                                                      │
│  FilteringWebHandler                                        │
│  ├── Global Filters                                         │
│  └── Gateway Filters                                        │
│      ↓                                                      │
│  后端服务 (异步调用)                                          │
│      ↓                                                      │
│  HTTP Response                                              │
│                                                             │
│  特点:基于 Reactor,非阻塞 IO,事件驱动模型                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 性能对比

特性 Zuul 1.x Spring Cloud Gateway
实现方式 Servlet 阻塞式 Reactor 非阻塞式
IO 模型 BIO NIO
性能 较低 较高(约 Zuul 的 1.6 倍)
并发能力 受线程池限制 高并发支持
长连接 支持 支持
WebSocket 不支持 支持
Spring 生态集成 一般 深度集成
维护状态 维护模式 活跃开发

1.3 性能测试数据

场景:1000 并发请求,平均响应时间测试

Zuul 1.x:
- 平均响应时间:50ms
- 吞吐量:约 20000 req/s
- CPU 使用率:较高

Spring Cloud Gateway:
- 平均响应时间:30ms
- 吞吐量:约 32000 req/s
- CPU 使用率:较低

二、核心概念

2.1 Route(路由)

路由是网关的基本构建块,由 ID、目标 URI、断言集合和过滤器集合组成。

@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/user/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Request-Id", UUID.randomUUID().toString()))
                .uri("lb://user-service"))
            .route("order-service", r -> r
                .path("/api/order/**")
                .filters(f -> f.stripPrefix(1))
                .uri("lb://order-service"))
            .build();
    }
}
# application.yml 配置方式
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-Id, ${value}

2.2 Predicate(断言)

断言用于匹配 HTTP 请求,决定是否走某个路由。

┌─────────────────────────────────────────────────────────────┐
│                     Predicate 类型                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  路径匹配:                                                   │
│  ├── Path=/api/user/**        匹配路径                       │
│  └── Path=/api/order/**,/api/pay/**  多路径匹配              │
│                                                             │
│  请求方法:                                                   │
│  ├── Method=GET               只匹配 GET 请求                │
│  └── Method=GET,POST          匹配 GET 和 POST               │
│                                                             │
│  请求头:                                                     │
│  ├── Header=X-Request-Id, \d+  Header 值匹配正则             │
│  └── Header=Content-Type, application/json                  │
│                                                             │
│  请求参数:                                                   │
│  ├── Query=token              存在 token 参数                │
│  └── Query=name, test.        name 值匹配正则                │
│                                                             │
│  Cookie:                                                    │
│  └── Cookie=session, abc.     Cookie 匹配                    │
│                                                             │
│  时间相关:                                                   │
│  ├── After=2024-01-01T00:00:00+08:00[Asia/Shanghai]         │
│  ├── Before=2024-12-31T23:59:59+08:00[Asia/Shanghai]        │
│  └── Between=...                                             │
│                                                             │
│  远程地址:                                                   │
│  └── RemoteAddr=192.168.1.1/24  IP 地址匹配                  │
│                                                             │
│  权重:                                                       │
│  └── Weight=group1, 80        80% 流量走此路由               │
│                                                             │
│  组合使用:                                                   │
│  predicates:                                                 │
│    - Path=/api/user/**                                       │
│    - Method=GET                                              │
│    - Header=Authorization, Bearer .*                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.3 Filter(过滤器)

过滤器用于修改请求和响应。

┌─────────────────────────────────────────────────────────────┐
│                     Filter 类型                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Pre Filter(请求前):                                       │
│  ├── AddRequestHeader        添加请求头                      │
│  ├── AddRequestParameter     添加请求参数                    │
│  ├── StripPrefix             去除路径前缀                    │
│  ├── PrefixPath              添加路径前缀                    │
│  ├── RewritePath             重写路径                        │
│  └── SetPath                 设置路径                        │
│                                                             │
│  Post Filter(响应后):                                      │
│  ├── AddResponseHeader       添加响应头                      │
│  ├── SetResponseHeader       设置响应头                      │
│  ├── SetStatus               设置响应状态码                  │
│  └── RemoveResponseHeader    移除响应头                      │
│                                                             │
│  功能 Filter:                                               │
│  ├── RequestRateLimiter      限流                            │
│  ├── CircuitBreaker          熔断                            │
│  ├── Retry                   重试                            │
│  └── RedirectTo              重定向                          │
│                                                             │
│  Global Filter(全局过滤器):                                │
│  └── 对所有路由生效                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

三、请求处理流程

3.1 核心组件

┌─────────────────────────────────────────────────────────────┐
│                  Gateway 核心组件                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  DispatcherHandler                                          │
│  └── WebFlux 核心分发器                                      │
│      ↓                                                      │
│  RoutePredicateHandlerMapping                               │
│  └── 路由映射,匹配 Predicate                                │
│      ↓                                                      │
│  GatewayHandlerAdapter                                      │
│  └── 适配器,执行 Handler                                    │
│      ↓                                                      │
│  FilteringWebHandler                                        │
│  └── 过滤器链执行                                            │
│      ├── 加载 GlobalFilter                                  │
│      ├── 加载 GatewayFilter                                 │
│      └── 按 Order 排序执行                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 完整请求流程图

┌────────────────────────────────────────────────────────────────────┐
│                    Gateway 请求处理流程                              │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│  HTTP Request                                                      │
│      ↓                                                             │
│  Reactor Netty Server                                              │
│      ↓                                                             │
│  DispatcherHandler                                                 │
│      ↓                                                             │
│  RoutePredicateHandlerMapping                                      │
│  ├── 遍历所有 Route                                                │
│  ├── 执行 Predicate 匹配                                           │
│  │   ├── Path 匹配                                                 │
│  │   ├── Method 匹配                                               │
│  │   ├── Header 匹配                                               │
│  │   └── ...                                                       │
│  └── 返回匹配的 Route                                              │
│      ↓                                                             │
│  GatewayHandlerAdapter                                             │
│      ↓                                                             │
│  FilteringWebHandler                                               │
│  ├── 加载所有 GlobalFilter                                         │
│  ├── 加载 Route 配置的 GatewayFilter                               │
│  ├── 按 Order 排序                                                 │
│  └── 执行过滤器链                                                   │
│      ↓                                                             │
│  【Pre Filter 阶段】                                                │
│  ├── 认证过滤器                                                    │
│  │   └── 验证 Token,无效则返回 401                               │
│  ├── 限流过滤器                                                    │
│  │   └── 检查限流,超限则返回 429                                  │
│  ├── 日志过滤器                                                    │
│  │   └── 记录请求信息                                              │
│  ├── StripPrefix                                                  │
│  │   └── 去除路径前缀                                              │
│  └── AddRequestHeader                                             │
│      └── 添加请求头                                                │
│      ↓                                                             │
│  【路由转发】                                                       │
│  LoadBalancerClientFilter                                         │
│  ├── 解析 lb:// 协议                                               │
│  ├── 从注册中心获取服务实例                                        │
│  ├── 负载均衡选择实例                                              │
│  └── 发送请求到后端服务                                            │
│      ↓                                                             │
│  【后端服务处理】                                                   │
│      ↓                                                             │
│  【Post Filter 阶段】                                               │
│  ├── AddResponseHeader                                            │
│  │   └── 添加响应头                                                │
│  ├── SetStatus                                                    │
│  │   └── 设置状态码                                                │
│  └── 日志过滤器                                                    │
│      └── 记录响应信息                                              │
│      ↓                                                             │
│  HTTP Response                                                     │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘

3.3 源码分析

DispatcherHandler

public class DispatcherHandler implements WebHandler {
    
    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        // 遍历 HandlerMapping
        return Flux.fromIterable(this.handlerMappings)
            .concatMap(mapping -> mapping.getHandler(exchange))
            .next()
            .switchIfEmpty(createNotFoundError())
            .flatMap(handler -> invokeHandler(exchange, handler))
            .onErrorResume(ex -> handleResultError(ex, exchange));
    }
}

RoutePredicateHandlerMapping

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    
    @Override
    protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
        // 查找匹配的路由
        return lookupRoute(exchange)
            .flatMap(route -> {
                exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);
                return Mono.just(webHandler);
            });
    }
    
    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        return getRouteLocator().getRoutes()
            .concatMap(route -> Mono.just(route)
                .filterWhen(r -> r.getPredicate().apply(exchange))
                .doOnNext(r -> exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r)))
            .next();
    }
}

FilteringWebHandler

public class FilteringWebHandler implements WebHandler {
    
    private final List<GatewayFilter> globalFilters;
    
    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
        
        // 合并 GlobalFilter 和 Route 的 GatewayFilter
        List<GatewayFilter> gatewayFilters = route.getFilters();
        List<GatewayFilter> combined = new ArrayList<>(globalFilters);
        combined.addAll(gatewayFilters);
        
        // 按 Order 排序
        AnnotationAwareOrderComparator.sort(combined);
        
        // 创建过滤器链
        return new DefaultGatewayFilterChain(combined).filter(exchange);
    }
}

// 过滤器链执行
public class DefaultGatewayFilterChain {
    
    public Mono<Void> filter(ServerWebExchange exchange) {
        return Mono.defer(() -> {
            if (this.index < filters.size()) {
                GatewayFilter filter = filters.get(this.index);
                return filter.filter(exchange, this.next);
            }
            return Mono.empty();
        });
    }
}

四、内置 Predicate 详解

4.1 Path 路径匹配

spring:
  cloud:
    gateway:
      routes:
        # 简单路径匹配
        - id: path-route
          uri: lb://user-service
          predicates:
            - Path=/api/user
        
        # 通配符匹配
        - id: wildcard-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
        
        # 多路径匹配
        - id: multi-path-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**,/api/users/**
        
        # 路径变量
        - id: path-variable-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/{id}
// 路径变量获取
@Component
public class UserIdFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取路径变量
        String userId = exchange.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)
            .get("id");
        // 使用变量...
        return chain.filter(exchange);
    }
}

4.2 Method 方法匹配

spring:
  cloud:
    gateway:
      routes:
        # 单方法匹配
        - id: get-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
            - Method=GET
        
        # 多方法匹配
        - id: post-put-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
            - Method=POST,PUT

4.3 Header 请求头匹配

spring:
  cloud:
    gateway:
      routes:
        # 存在 Header
        - id: header-exist-route
          uri: lb://user-service
          predicates:
            - Header=X-Request-Id
        
        # Header 值匹配正则
        - id: header-regex-route
          uri: lb://user-service
          predicates:
            - Header=X-Request-Id, \d+  # 数字
        
        # 认证 Header
        - id: auth-route
          uri: lb://user-service
          predicates:
            - Path=/api/secure/**
            - Header=Authorization, Bearer .+

4.4 Query 参数匹配

spring:
  cloud:
    gateway:
      routes:
        # 存在参数
        - id: query-exist-route
          uri: lb://user-service
          predicates:
            - Query=token
        
        # 参数值匹配正则
        - id: query-regex-route
          uri: lb://user-service
          predicates:
            - Query=name, test.  # test 开头
        
        # 组合参数
        - id: multi-query-route
          uri: lb://user-service
          predicates:
            - Query=token
            - Query=version,v1
spring:
  cloud:
    gateway:
      routes:
        # Cookie 匹配
        - id: cookie-route
          uri: lb://user-service
          predicates:
            - Cookie=session, ^[a-z0-9]+$

4.6 时间匹配

spring:
  cloud:
    gateway:
      routes:
        # 指定时间之后
        - id: after-route
          uri: lb://user-service
          predicates:
            - After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
        
        # 指定时间之前
        - id: before-route
          uri: lb://user-service
          predicates:
            - Before=2024-12-31T23:59:59+08:00[Asia/Shanghai]
        
        # 时间区间
        - id: between-route
          uri: lb://user-service
          predicates:
            - Between=2024-01-01T00:00:00+08:00[Asia/Shanghai], 2024-12-31T23:59:59+08:00[Asia/Shanghai]

4.7 RemoteAddr 地址匹配

spring:
  cloud:
    gateway:
      routes:
        # 单个 IP
        - id: ip-route
          uri: lb://user-service
          predicates:
            - RemoteAddr=192.168.1.100
        
        # IP 段
        - id: ip-segment-route
          uri: lb://user-service
          predicates:
            - RemoteAddr=192.168.1.0/24
        
        # 多个 IP 段
        - id: multi-ip-route
          uri: lb://user-service
          predicates:
            - RemoteAddr=192.168.1.0/24,10.0.0.0/8

4.8 Weight 权重匹配

spring:
  cloud:
    gateway:
      routes:
        # 80% 流量
        - id: weight-high-route
          uri: lb://user-service-v2
          predicates:
            - Weight=group1, 80
        
        # 20% 流量
        - id: weight-low-route
          uri: lb://user-service-v1
          predicates:
            - Weight=group1, 20

五、内置 Filter 详解

5.1 请求头相关

spring:
  cloud:
    gateway:
      routes:
        - id: header-filter-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            # 添加请求头
            - AddRequestHeader=X-Request-Foo, Bar
            - AddRequestHeader=X-Request-Time, ${time}
            
            # 设置请求头(覆盖)
            - SetRequestHeader=X-Request-Id, ${value}
            
            # 移除请求头
            - RemoveRequestHeader=X-Request-Unwanted
            
            # 添加请求参数
            - AddRequestParameter=foo, bar
            
            # 移除请求参数
            - RemoveRequestParameter=unwanted

5.2 路径相关

spring:
  cloud:
    gateway:
      routes:
        - id: path-filter-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            # 去除路径前缀
            # /api/user/list -> /user/list
            - StripPrefix=1
            
            # 添加路径前缀
            # /list -> /api/user/list
            - PrefixPath=/api/user
            
            # 重写路径
            # /api/user/(?<segment>.*) -> /${segment}
            - RewritePath=/api/user/(?<segment>.*), /${segment}
            
            # 设置路径
            - SetPath=/api/user/{segment}

5.3 响应头相关

spring:
  cloud:
    gateway:
      routes:
        - id: response-filter-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            # 添加响应头
            - AddResponseHeader=X-Response-Foo, Bar
            
            # 设置响应头
            - SetResponseHeader=X-Response-Time, ${time}
            
            # 移除响应头
            - RemoveResponseHeader=X-Response-Unwanted
            
            # 设置状态码
            - SetStatus=200

5.4 重定向

spring:
  cloud:
    gateway:
      routes:
        # 302 重定向
        - id: redirect-route
          uri: lb://user-service
          predicates:
            - Path=/old-path
          filters:
            - RedirectTo=302, https://example.com/new-path

5.5 重试机制

spring:
  cloud:
    gateway:
      routes:
        - id: retry-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - name: Retry
              args:
                retries: 3                    # 重试次数
                statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE  # 触发重试的状态码
                methods: GET,POST             # 触发重试的方法
                backoff:
                  firstBackoff: 100ms         # 首次重试等待时间
                  maxBackoff: 500ms           # 最大等待时间
                  factor: 2                   # 退避因子
                  basedOnPreviousValue: false

六、自定义 GlobalFilter

6.1 认证过滤器

@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    @Value("${auth.enabled:true}")
    private boolean authEnabled;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        
        // 白名单路径
        if (isWhitePath(path)) {
            return chain.filter(exchange);
        }
        
        // 获取 Token
        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            return unauthorized(exchange, "缺少认证信息");
        }
        
        // 验证 Token
        try {
            // 去除 Bearer 前缀
            if (token.startsWith("Bearer ")) {
                token = token.substring(7);
            }
            
            // JWT 验证
            Claims claims = JwtUtil.parseToken(token);
            String userId = claims.getSubject();
            
            // 将用户信息放入 Header
            ServerHttpRequest newRequest = request.mutate()
                .header("X-User-Id", userId)
                .header("X-User-Name", claims.get("name", String.class))
                .build();
            
            return chain.filter(exchange.mutate().request(newRequest).build());
            
        } catch (ExpiredJwtException e) {
            return unauthorized(exchange, "Token 已过期");
        } catch (Exception e) {
            log.error("Token 验证失败", e);
            return unauthorized(exchange, "Token 无效");
        }
    }
    
    private boolean isWhitePath(String path) {
        List<String> whiteList = Arrays.asList(
            "/api/auth/login",
            "/api/auth/register",
            "/api/health",
            "/actuator/**"
        );
        return whiteList.stream().anyMatch(path::startsWith);
    }
    
    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        Map<String, Object> result = new HashMap<>();
        result.put("code", 401);
        result.put("message", message);
        result.put("timestamp", System.currentTimeMillis());
        
        byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -100;  // 高优先级
    }
}

6.2 日志过滤器

@Component
@Slf4j
public class RequestLogGlobalFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
        exchange.getAttributes().put("startTime", startTime);
        
        // 记录请求信息
        String requestId = UUID.randomUUID().toString();
        exchange.getAttributes().put("requestId", requestId);
        
        log.info("[{}] Request: {} {} from {}",
            requestId,
            request.getMethod(),
            request.getPath(),
            request.getRemoteAddress()
        );
        
        // 响应后记录日志
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            Long start = exchange.getAttribute("startTime");
            if (start != null) {
                long duration = System.currentTimeMillis() - start;
                ServerHttpResponse response = exchange.getResponse();
                
                log.info("[{}] Response: {} {}ms",
                    requestId,
                    response.getStatusCode(),
                    duration
                );
            }
        }));
    }
    
    @Override
    public int getOrder() {
        return -200;  // 最高优先级
    }
}

6.3 跨域过滤器

@Component
public class CorsGlobalFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        
        HttpHeaders headers = response.getHeaders();
        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
        headers.add("Access-Control-Allow-Headers", "*");
        headers.add("Access-Control-Max-Age", "3600");
        
        // OPTIONS 请求直接返回
        if (request.getMethod() == HttpMethod.OPTIONS) {
            response.setStatusCode(HttpStatus.OK);
            return response.setComplete();
        }
        
        return chain.filter(exchange);
    }
    
    @Override
    public int getOrder() {
        return -300;
    }
}

七、自定义 PredicateFactory

7.1 自定义时间范围断言

@Component
public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig> {
    
    public TimeBetweenRoutePredicateFactory() {
        super(TimeBetweenConfig.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
        return exchange -> {
            LocalTime now = LocalTime.now();
            return now.isAfter(config.getStartTime()) && now.isBefore(config.getEndTime());
        };
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("startTime", "endTime");
    }
    
    public static class TimeBetweenConfig {
        private LocalTime startTime;
        private LocalTime endTime;
        
        // getter/setter
    }
}
# 使用自定义断言
spring:
  cloud:
    gateway:
      routes:
        - id: time-route
          uri: lb://user-service
          predicates:
            - TimeBetween=08:00,18:00  # 只在 8:00-18:00 生效

八、限流:RequestRateLimiter

8.1 令牌桶算法原理

┌─────────────────────────────────────────────────────────────┐
│                     令牌桶算法                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────┐               │
│  │           令牌桶 (Token Bucket)          │               │
│  │                                         │               │
│  │   ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐       │               │
│  │   │ T │ │ T │ │ T │ │   │ │   │       │               │
│  │   └───┘ └───┘ └───┘ └───┘ └───┘       │               │
│  │                                         │               │
│  │   当前令牌数: 3   桶容量: 5             │               │
│  └─────────────────────────────────────────┘               │
│                     ↑                                       │
│            按固定速率生成令牌                                  │
│            (replenishRate: 10/s)                            │
│                                                             │
│  请求到达:                                                   │
│  ├── 有令牌 → 取走令牌 → 请求通过                            │
│  └── 无令牌 → 请求被拒绝 → 返回 429                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

8.2 基于内存的限流

@Configuration
public class RateLimiterConfig {
    
    @Bean
    public KeyResolver ipKeyResolver() {
        // 按 IP 限流
        return exchange -> Mono.just(
            exchange.getRequest()
                .getRemoteAddress()
                .getAddress()
                .getHostAddress()
        );
    }
    
    @Bean
    public KeyResolver userKeyResolver() {
        // 按用户限流
        return exchange -> Mono.just(
            exchange.getRequest()
                .getHeaders()
                .getFirst("X-User-Id")
        );
    }
    
    @Bean
    public KeyResolver apiKeyResolver() {
        // 按 API 路径限流
        return exchange -> Mono.just(
            exchange.getRequest().getPath().value()
        );
    }
}
spring:
  cloud:
    gateway:
      routes:
        - id: rate-limit-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - name: RequestRateLimiter
              args:
                # 每秒生成令牌数
                replenishRate: 10
                # 桶容量
                burstCapacity: 20
                # 每次请求消耗令牌数
                requestedTokens: 1
                # KeyResolver Bean 名称
                key-resolver: "#{@ipKeyResolver}"

8.3 基于 Redis 的分布式限流

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
spring:
  redis:
    host: localhost
    port: 6379
    password: ${REDIS_PASSWORD}
  cloud:
    gateway:
      routes:
        - id: redis-rate-limit-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                redis-rate-limiter.requestedTokens: 1
                key-resolver: "#{@ipKeyResolver}"
// 自定义限流配置
@Bean
public RedisRateLimiter customRedisRateLimiter() {
    return new RedisRateLimiter(10, 20);
}

8.4 限流响应处理

@Component
public class RateLimiterExceptionHandler implements WebExceptionHandler {
    
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (ex instanceof RequestNotPermittedException) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            
            Map<String, Object> result = new HashMap<>();
            result.put("code", 429);
            result.put("message", "请求过于频繁,请稍后再试");
            result.put("timestamp", System.currentTimeMillis());
            
            byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            
            return response.writeWith(Mono.just(buffer));
        }
        return Mono.error(ex);
    }
}

九、熔断:CircuitBreaker

9.1 添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

9.2 配置熔断

spring:
  cloud:
    gateway:
      routes:
        - id: circuit-breaker-route
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/user

# Resilience4j 配置
resilience4j:
  circuitbreaker:
    configs:
      default:
        slidingWindowType: COUNT_BASED
        slidingWindowSize: 10
        minimumNumberOfCalls: 5
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 3
    instances:
      userServiceCircuitBreaker:
        baseConfig: default

9.3 降级处理

@RestController
@RequestMapping("/fallback")
public class FallbackController {
    
    @GetMapping("/user")
    public Mono<Map<String, Object>> userFallback() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "用户服务暂时不可用,请稍后再试");
        result.put("timestamp", System.currentTimeMillis());
        return Mono.just(result);
    }
    
    @GetMapping("/order")
    public Mono<Map<String, Object>> orderFallback() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "订单服务暂时不可用,请稍后再试");
        result.put("timestamp", System.currentTimeMillis());
        return Mono.just(result);
    }
}

📖 高频面试题

Q1: Spring Cloud Gateway 的核心组件有哪些?

答:

1. Route(路由)

2. Predicate(断言)

3. Filter(过滤器)

4. 核心处理器

Q2: Gateway 和 Zuul 的区别?

答:

特性 Zuul 1.x Spring Cloud Gateway
架构 Servlet 阻塞式 Reactor 非阻塞式
IO 模型 BIO NIO
性能 较低 较高
并发能力 受线程池限制 高并发支持
WebSocket 不支持 支持
线程模型 每请求一线程 事件驱动
背压支持 不支持 支持

Q3: Gateway 如何实现限流?

答:

1. 内置 RequestRateLimiter

2. 配置方式

filters:
  - name: RequestRateLimiter
    args:
      redis-rate-limiter.replenishRate: 10  # 每秒生成令牌数
      redis-rate-limiter.burstCapacity: 20  # 桶容量
      key-resolver: "#{@ipKeyResolver}"     # 限流 Key

3. KeyResolver

Q4: Gateway 如何实现熔断?

答:

1. 集成 Resilience4j

filters:
  - name: CircuitBreaker
    args:
      name: myCircuitBreaker
      fallbackUri: forward:/fallback

2. 熔断状态

3. 降级处理

Q5: Gateway 如何实现认证?

答:

1. 自定义 GlobalFilter

@Component
public class AuthGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. 白名单检查
        // 2. Token 获取和验证
        // 3. 用户信息传递
        // 4. 无效则返回 401
    }
}

2. 配置顺序

3. 安全配置


参考链接: