核心概念

Spring Cloud Gateway是SpringCloud官方推出的新一代API网关,基于Spring WebFlux(响应式编程)实现,提供路由转发、负载均衡、限流、熔断、认证等功能,性能优于Zuul。

Gateway vs Zuul

对比项 Zuul 1.x Gateway Zuul 2.x
技术栈 Servlet(阻塞) WebFlux(非阻塞) Netty(非阻塞)
性能 一般
维护方 Netflix Spring官方 Netflix
生态集成 较好 完美 一般
推荐度 不推荐 推荐 较少使用

架构图

Client Request
     ↓
┌─────────────────────────────────────┐
│      Spring Cloud Gateway           │
│  ┌───────────────────────────────┐  │
│  │  Handler Mapping              │  │
│  │  (路由匹配)                    │  │
│  └─────────────┬─────────────────┘  │
│                ↓                     │
│  ┌───────────────────────────────┐  │
│  │  Gateway Handler              │  │
│  │  (执行过滤器链)                │  │
│  └─────────────┬─────────────────┘  │
│                ↓                     │
│  ┌───────────────────────────────┐  │
│  │  Pre Filters                  │  │
│  │  (前置过滤器)                  │  │
│  └─────────────┬─────────────────┘  │
│                ↓                     │
│  ┌───────────────────────────────┐  │
│  │  Routing Filter               │  │
│  │  (路由到目标服务)              │  │
│  └─────────────┬─────────────────┘  │
│                ↓                     │
│  ┌───────────────────────────────┐  │
│  │  Post Filters                 │  │
│  │  (后置过滤器)                  │  │
│  └─────────────┬─────────────────┘  │
└─────────────────┼───────────────────┘
                  ↓
            Target Service

核心组件

1. Route(路由)

路由是Gateway的基本构建块,包含:

  • ID:路由唯一标识
  • 目标URI:请求转发的目标地址
  • Predicates:路由匹配条件
  • Filters:过滤器链
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
        .route("user_route", r -> r
            .path("/api/users/**")  // Predicate: 路径匹配
            .filters(f -> f
                .stripPrefix(1)  // Filter: 去掉路径前缀
                .addRequestHeader("X-Request-Source", "Gateway"))
            .uri("lb://user-service"))  // 目标URI(负载均衡)
        .build();
}

2. Predicate(断言/谓词)

判断请求是否匹配路由的条件,类似于if判断。

内置Predicate工厂

spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            # 路径匹配
            - Path=/api/users/**
            
            # 请求方法匹配
            - Method=GET,POST
            
            # 请求头匹配
            - Header=X-Request-Id, \d+  # 正则表达式
            
            # 查询参数匹配
            - Query=token
            - Query=userId, \d+  # 带值匹配
            
            # Cookie匹配
            - Cookie=session, abc.*
            
            # 主机匹配
            - Host=**.example.com
            
            # IP地址匹配
            - RemoteAddr=192.168.1.1/24
            
            # 时间匹配
            - After=2025-01-01T00:00:00+08:00[Asia/Shanghai]
            - Before=2025-12-31T23:59:59+08:00[Asia/Shanghai]
            - Between=2025-01-01T00:00:00+08:00,2025-12-31T23:59:59+08:00
            
            # 权重匹配(用于金丝雀发布)
            - Weight=group1, 8  # 80%流量

自定义Predicate

@Component
public class CustomRoutePredicateFactory 
    extends AbstractRoutePredicateFactory<CustomRoutePredicateFactory.Config> {
    
    public CustomRoutePredicateFactory() {
        super(Config.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            // 自定义匹配逻辑
            String userType = exchange.getRequest()
                .getHeaders()
                .getFirst("User-Type");
            
            return config.getUserType().equals(userType);
        };
    }
    
    public static class Config {
        private String userType;
        
        public String getUserType() {
            return userType;
        }
        
        public void setUserType(String userType) {
            this.userType = userType;
        }
    }
}

使用:

predicates:
  - Custom=vip  # 自定义断言

3. Filter(过滤器)

对请求和响应进行处理,类似于Servlet Filter。

内置Filter工厂

spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          filters:
            # 去掉路径前缀(/api/users/1 → /users/1)
            - StripPrefix=1
            
            # 添加路径前缀(/users/1 → /v1/users/1)
            - PrefixPath=/v1
            
            # 添加请求头
            - AddRequestHeader=X-Request-Source, Gateway
            - AddRequestParameter=version, 1.0
            
            # 添加响应头
            - AddResponseHeader=X-Response-Time, ${timestamp}
            
            # 移除请求头
            - RemoveRequestHeader=Cookie
            - RemoveResponseHeader=Set-Cookie
            
            # 重写路径
            - RewritePath=/api/(?<segment>.*), /$\{segment}
            
            # 设置响应状态码
            - SetStatus=200
            
            # 重定向
            - RedirectTo=302, https://www.example.com
            
            # 限流
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10  # 每秒生成令牌数
                redis-rate-limiter.burstCapacity: 20  # 令牌桶容量
                key-resolver: "#{@ipKeyResolver}"  # Key解析器
            
            # 熔断
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/fallback
            
            # 重试
            - name: Retry
              args:
                retries: 3
                statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
                methods: GET,POST
                backoff:
                  firstBackoff: 100ms
                  maxBackoff: 500ms
                  factor: 2

全局Filter

@Component
@Order(-1)  // 优先级(数字越小优先级越高)
public class GlobalAuthFilter implements GlobalFilter {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 1. 前置处理
        String token = request.getHeaders().getFirst("Authorization");
        
        if (token == null || !validateToken(token)) {
            // 认证失败,返回401
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        
        // 2. 添加用户信息到请求头
        ServerHttpRequest mutatedRequest = request.mutate()
            .header("X-User-Id", getUserIdFromToken(token))
            .build();
        
        ServerWebExchange mutatedExchange = exchange.mutate()
            .request(mutatedRequest)
            .build();
        
        // 3. 继续执行过滤器链
        return chain.filter(mutatedExchange).then(Mono.fromRunnable(() -> {
            // 4. 后置处理
            ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add("X-Gateway-Response", "success");
        }));
    }
    
    private boolean validateToken(String token) {
        // JWT验证逻辑
        return true;
    }
    
    private String getUserIdFromToken(String token) {
        // 解析Token获取用户ID
        return "123456";
    }
}

自定义GatewayFilter

@Component
public class CustomGatewayFilterFactory 
    extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {
    
    public CustomGatewayFilterFactory() {
        super(Config.class);
    }
    
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            
            // 前置处理
            log.info("请求路径: {}", request.getURI().getPath());
            
            // 修改请求
            ServerHttpRequest modifiedRequest = request.mutate()
                .header("X-Custom-Header", config.getValue())
                .build();
            
            // 继续执行
            return chain.filter(exchange.mutate().request(modifiedRequest).build())
                .then(Mono.fromRunnable(() -> {
                    // 后置处理
                    ServerHttpResponse response = exchange.getResponse();
                    log.info("响应状态码: {}", response.getStatusCode());
                }));
        };
    }
    
    public static class Config {
        private String value;
        
        public String getValue() {
            return value;
        }
        
        public void setValue(String value) {
            this.value = value;
        }
    }
}

核心源码解析

1. 路由匹配流程

// RoutePredicateHandlerMapping 路由匹配入口
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    
    @Override
    protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
        // 1. 查找匹配的路由
        return lookupRoute(exchange)
            .flatMap(route -> {
                // 2. 将匹配的路由保存到exchange
                exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, route);
                return Mono.just(webHandler);
            })
            .switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                // 3. 未找到匹配路由
                exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
            })));
    }
    
    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        return this.routeLocator.getRoutes()
            // 遍历所有路由
            .concatMap(route -> Mono.just(route)
                .filterWhen(r -> {
                    // 测试Predicate是否匹配
                    exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                    return r.getPredicate().apply(exchange);
                })
                .doOnError(e -> log.error("路由匹配错误", e))
                .onErrorResume(e -> Mono.empty()))
            // 取第一个匹配的路由
            .next();
    }
}

2. 过滤器链执行

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

// DefaultGatewayFilterChain 过滤器链
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
    private final int index;
    private final List<GatewayFilter> filters;
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange) {
        // 递归执行过滤器
        if (this.index < filters.size()) {
            GatewayFilter filter = filters.get(this.index);
            DefaultGatewayFilterChain chain = 
                new DefaultGatewayFilterChain(this, this.index + 1);
            return filter.filter(exchange, chain);
        } else {
            return Mono.empty();  // 过滤器执行完毕
        }
    }
}

3. 路由转发

// NettyRoutingFilter 执行实际的HTTP请求
public class NettyRoutingFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);
        
        // 1. 构建HTTP请求
        HttpMethod method = exchange.getRequest().getMethod();
        
        return this.httpClient.request(method)
            .uri(requestUrl)
            .send((req, nettyOutbound) -> {
                // 2. 发送请求体
                return nettyOutbound.send(exchange.getRequest().getBody()
                    .map(dataBuffer -> {
                        return nettyOutbound.alloc().wrap(dataBuffer.asByteBuffer());
                    }));
            })
            .responseConnection((res, connection) -> {
                // 3. 处理响应
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.valueOf(res.status().code()));
                response.getHeaders().putAll(res.responseHeaders());
                
                // 4. 写入响应体
                return response.writeWith(connection.inbound().receive()
                    .map(byteBuf -> {
                        return response.bufferFactory().wrap(byteBuf.nioBuffer());
                    }));
            })
            .then(chain.filter(exchange));
    }
    
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;  // 最后执行
    }
}

限流实现

基于Redis的令牌桶限流

// RedisRateLimiter 核心实现
public class RedisRateLimiter implements RateLimiter<RedisRateLimiter.Config> {
    
    @Override
    public Mono<Response> isAllowed(String routeId, String id) {
        Config config = getConfig().get(routeId);
        
        // 令牌桶参数
        int replenishRate = config.getReplenishRate();  // 每秒生成令牌数
        int burstCapacity = config.getBurstCapacity();  // 桶容量
        
        // Lua脚本(保证原子性)
        List<String> keys = Arrays.asList(
            routeId + ".tokens",  // 当前令牌数
            routeId + ".timestamp"  // 上次填充时间
        );
        
        return redisTemplate.execute(script, keys, 
            replenishRate, burstCapacity, Instant.now().getEpochSecond(), 1)
            .map(results -> {
                boolean allowed = (Long) results.get(0) == 1L;
                long tokensLeft = (Long) results.get(1);
                
                return new Response(allowed, 
                    getHeaders(config, tokensLeft));
            });
    }
}

Lua脚本:

-- 令牌桶算法
local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]

local rate = tonumber(ARGV[1])  -- 每秒生成令牌数
local capacity = tonumber(ARGV[2])  -- 桶容量
local now = tonumber(ARGV[3])  -- 当前时间
local requested = tonumber(ARGV[4])  -- 请求令牌数

-- 获取当前令牌数和上次填充时间
local tokens = tonumber(redis.call("get", tokens_key))
if tokens == nil then
  tokens = capacity
end

local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end

-- 计算新增令牌
local delta = math.max(0, now - last_refreshed)
local filled_tokens = math.min(capacity, tokens + (delta * rate))

-- 判断是否允许请求
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
if allowed then
  new_tokens = filled_tokens - requested
end

-- 更新Redis
redis.call("setex", tokens_key, 3600, new_tokens)
redis.call("setex", timestamp_key, 3600, now)

return {allowed, new_tokens}

Key解析器

@Configuration
public class KeyResolverConfig {
    
    // 基于IP限流
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest()
                .getRemoteAddress()
                .getAddress()
                .getHostAddress()
        );
    }
    
    // 基于用户限流
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest()
                .getHeaders()
                .getFirst("X-User-Id")
        );
    }
    
    // 基于API限流
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest()
                .getPath()
                .value()
        );
    }
}

统一异常处理

@Component
@Order(-1)
public class GlobalExceptionHandler implements WebExceptionHandler {
    
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        
        if (response.isCommitted()) {
            return Mono.error(ex);
        }
        
        // 设置响应头
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        // 构建错误响应
        ErrorResponse errorResponse = new ErrorResponse();
        
        if (ex instanceof ResponseStatusException) {
            ResponseStatusException rse = (ResponseStatusException) ex;
            response.setStatusCode(rse.getStatus());
            errorResponse.setCode(rse.getStatus().value());
            errorResponse.setMessage(rse.getReason());
        } else if (ex instanceof TimeoutException) {
            response.setStatusCode(HttpStatus.GATEWAY_TIMEOUT);
            errorResponse.setCode(504);
            errorResponse.setMessage("请求超时");
        } else {
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            errorResponse.setCode(500);
            errorResponse.setMessage("服务器内部错误");
        }
        
        // 写入响应
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            try {
                byte[] bytes = new ObjectMapper().writeValueAsBytes(errorResponse);
                return bufferFactory.wrap(bytes);
            } catch (Exception e) {
                return bufferFactory.wrap(new byte[0]);
            }
        }));
    }
}

跨域配置

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOriginPatterns: "*"  # 允许的源
            allowedMethods:  # 允许的方法
              - GET
              - POST
              - PUT
              - DELETE
              - OPTIONS
            allowedHeaders: "*"  # 允许的请求头
            allowCredentials: true  # 允许携带Cookie
            maxAge: 3600  # 预检请求缓存时间

最佳实践

1. 统一前缀配置

spring:
  cloud:
    gateway:
      default-filters:
        - PrefixPath=/api  # 所有路由统一添加/api前缀
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/users/**
          # 实际请求路径: /api/users/**

2. 超时配置

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 3000  # 连接超时
        response-timeout: 5s  # 响应超时
      routes:
        - id: slow_route
          uri: lb://slow-service
          predicates:
            - Path=/slow/**
          metadata:
            response-timeout: 30000  # 针对特定路由
            connect-timeout: 10000

3. 熔断配置

spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/users
                
resilience4j:
  circuitbreaker:
    instances:
      userServiceCircuitBreaker:
        sliding-window-size: 10  # 滑动窗口大小
        failure-rate-threshold: 50  # 失败率阈值
        wait-duration-in-open-state: 10s  # 熔断等待时间

面试总结

Spring Cloud Gateway工作原理

  1. 路由匹配RoutePredicateHandlerMapping根据Predicates匹配请求到具体路由
  2. 过滤器链FilteringWebHandler构建并执行全局过滤器和路由过滤器链
  3. 请求转发NettyRoutingFilter使用Netty客户端转发请求到目标服务
  4. 响应处理:通过过滤器链处理响应,最后返回给客户端

核心组件

  • Route:路由规则(ID + URI + Predicates + Filters)
  • Predicate:路由匹配条件(Path、Method、Header等)
  • Filter:请求/响应处理(全局Filter和GatewayFilter)

技术特点

  • 基于WebFlux响应式编程,性能优于Zuul
  • 使用Netty作为底层HTTP客户端
  • 天然集成Spring生态(Eureka、Hystrix、Ribbon)

常见应用:路由转发、负载均衡、限流、熔断、认证鉴权、日志记录、跨域处理

推荐指数:⭐⭐⭐⭐⭐(SpringCloud官方推荐的网关方案)