Skip to content

Spring Cloud Gateway

Spring Cloud Gateway是基于Spring Boot 2.x、Spring WebFlux和Project Reactor构建的响应式API网关,为微服务架构提供简单、有效且统一的API路由方式。

核心特性

响应式架构

  • 非阻塞I/O - 基于Netty和Spring WebFlux实现
  • 背压支持 - 天然支持流量控制和背压处理
  • 高并发 - 支持大量并发连接,资源利用率高
  • 内存效率 - 相比传统阻塞式网关,内存使用更高效

路由功能

  • 动态路由 - 支持运行时动态修改路由配置
  • 路径重写 - 灵活的URL路径转换和重写
  • 负载均衡 - 集成Spring Cloud LoadBalancer
  • 服务发现 - 与Eureka、Consul、Nacos等注册中心集成

过滤器机制

  • 全局过滤器 - 应用于所有路由的过滤逻辑
  • 路由过滤器 - 特定路由的过滤处理
  • 自定义过滤器 - 灵活扩展业务逻辑
  • 过滤器链 - 支持多个过滤器的链式处理

核心概念

基本组件

  • Route - 路由,网关的基本构建块
  • Predicate - 谓词,用于匹配HTTP请求
  • Filter - 过滤器,处理请求和响应
  • Gateway Handler Mapping - 路由映射处理器

执行流程

请求执行流程:
1. 客户端请求到达Gateway
2. Gateway Handler Mapping确定路由
3. 发送到Gateway Web Handler
4. 通过过滤器链处理请求
5. 代理请求到下游服务
6. 通过过滤器链处理响应
7. 返回响应给客户端

快速开始

Maven依赖

点击查看完整代码实现
xml
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    
    <!-- 服务发现 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
    <!-- 限流 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
</dependencies>

基础配置

application.yml配置

点击查看完整代码实现
yaml
server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      # 全局CORS配置
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origins: "*"
            allowed-methods: "*"
            allowed-headers: "*"
            allow-credentials: true
      
      # 路由配置
      routes:
        # 用户服务路由
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=2
            - AddRequestHeader=X-Request-Source, gateway
            - AddResponseHeader=X-Response-Source, gateway
        
        # 订单服务路由
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Method=GET,POST
          filters:
            - StripPrefix=2
            - RewritePath=/api/orders/(?<segment>.*), /orders/$\{segment}
        
        # 商品服务路由
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
            - Header=X-Request-Id, \d+
          filters:
            - StripPrefix=2
            - RequestRateLimiter=#{@redisRateLimiter}
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@userKeyResolver}"

# 服务发现配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

# Redis配置(用于限流)
  redis:
    host: localhost
    port: 6379
    database: 0

基础示例

网关主类

点击查看完整代码实现
java
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
    
    // 用户限流Key解析器
    @Bean
    @Primary
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just("user");
    }
    
    // IP限流Key解析器
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
    
    // 路径限流Key解析器
    @Bean  
    public KeyResolver pathKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }
}

Java配置方式

点击查看完整代码实现
java
@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            // 用户服务路由
            .route("user-service", r -> r
                .path("/api/users/**")
                .and()
                .method(HttpMethod.GET, HttpMethod.POST)
                .filters(f -> f
                    .stripPrefix(2)
                    .addRequestHeader("X-Request-Source", "gateway")
                    .addResponseHeader("X-Response-Source", "gateway")
                    .retry(config -> config
                        .retries(3)
                        .series(HttpStatus.Series.SERVER_ERROR)
                        .backoff(Duration.ofSeconds(1), Duration.ofSeconds(10), 2, false)
                    )
                )
                .uri("lb://user-service")
            )
            // 重定向路由
            .route("redirect-route", r -> r
                .path("/old-api/**")
                .filters(f -> f.redirect(302, "/new-api"))
                .uri("no://op")
            )
            // 限流路由
            .route("throttle-route", r -> r
                .path("/api/throttle/**")
                .filters(f -> f
                    .requestRateLimiter(config -> config
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(exchange -> Mono.just("throttle"))
                    )
                )
                .uri("lb://throttle-service")
            )
            .build();
    }
    
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20, 1);
    }
}

路由谓词

内置谓词

点击查看完整代码实现
yaml
spring:
  cloud:
    gateway:
      routes:
        # 时间相关谓词
        - id: after-route
          uri: lb://service
          predicates:
            - After=2024-01-01T00:00:00.000+08:00[Asia/Shanghai]
        
        - id: before-route
          uri: lb://service
          predicates:
            - Before=2024-12-31T23:59:59.999+08:00[Asia/Shanghai]
        
        - id: between-route
          uri: lb://service
          predicates:
            - Between=2024-01-01T00:00:00.000+08:00[Asia/Shanghai], 2024-12-31T23:59:59.999+08:00[Asia/Shanghai]
        
        # 请求相关谓词
        - id: cookie-route
          uri: lb://service
          predicates:
            - Cookie=sessionId, \w+
        
        - id: header-route
          uri: lb://service
          predicates:
            - Header=X-Request-Id, \d+
        
        - id: host-route
          uri: lb://service
          predicates:
            - Host=api.example.com,gateway.example.com
        
        - id: method-route
          uri: lb://service
          predicates:
            - Method=GET,POST
        
        - id: path-route
          uri: lb://service
          predicates:
            - Path=/api/v1/**,/api/v2/**
        
        - id: query-route
          uri: lb://service
          predicates:
            - Query=version, v\d+
        
        - id: remote-addr-route
          uri: lb://service
          predicates:
            - RemoteAddr=192.168.1.0/24
        
        # 权重路由
        - id: weight-high
          uri: lb://service-v2
          predicates:
            - Weight=group1, 8
        
        - id: weight-low
          uri: lb://service-v1
          predicates:
            - Weight=group1, 2

自定义谓词

点击查看完整代码实现
java
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
    
    public MyRoutePredicateFactory() {
        super(Config.class);
    }
    
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            // 自定义匹配逻辑
            String userAgent = exchange.getRequest().getHeaders().getFirst("User-Agent");
            return userAgent != null && userAgent.contains(config.getUserAgent());
        };
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("userAgent");
    }
    
    public static class Config {
        private String userAgent;
        
        // getter and setter
        public String getUserAgent() {
            return userAgent;
        }
        
        public void setUserAgent(String userAgent) {
            this.userAgent = userAgent;
        }
    }
}

过滤器开发

全局过滤器

点击查看完整代码实现
java
@Component
@Order(1)
public class AuthGlobalFilter implements GlobalFilter {
    
    private static final String AUTH_TOKEN = "Authorization";
    private static final List<String> EXCLUDE_PATHS = Arrays.asList(
        "/api/auth/login", "/api/auth/register", "/actuator/health"
    );
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().pathWithinApplication().value();
        
        // 排除不需要认证的路径
        if (EXCLUDE_PATHS.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }
        
        // 检查认证token
        String token = request.getHeaders().getFirst(AUTH_TOKEN);
        if (StringUtils.isEmpty(token)) {
            return unauthorized(exchange.getResponse());
        }
        
        // 验证token
        return validateToken(token)
            .flatMap(valid -> {
                if (valid) {
                    // 添加用户信息到请求头
                    ServerHttpRequest newRequest = request.mutate()
                        .header("X-User-Id", getUserId(token))
                        .header("X-User-Role", getUserRole(token))
                        .build();
                    return chain.filter(exchange.mutate().request(newRequest).build());
                } else {
                    return unauthorized(exchange.getResponse());
                }
            });
    }
    
    private Mono<Void> unauthorized(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        
        String body = "{\"code\":401,\"message\":\"Unauthorized\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    }
    
    private Mono<Boolean> validateToken(String token) {
        // 异步验证token
        return Mono.fromCallable(() -> {
            // 模拟token验证逻辑
            return token.startsWith("Bearer ") && token.length() > 20;
        })
        .subscribeOn(Schedulers.boundedElastic());
    }
    
    private String getUserId(String token) {
        // 从token中提取用户ID
        return "user123";
    }
    
    private String getUserRole(String token) {
        // 从token中提取用户角色
        return "USER";
    }
}

日志过滤器

点击查看完整代码实现
java
@Component
@Order(2)
public class LoggingGlobalFilter implements GlobalFilter {
    
    private static final Logger log = LoggerFactory.getLogger(LoggingGlobalFilter.class);
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 记录请求信息
        String requestId = UUID.randomUUID().toString();
        log.info("Gateway Request: {} {} {} from {}",
            requestId,
            request.getMethod(),
            request.getPath().pathWithinApplication().value(),
            request.getRemoteAddress()
        );
        
        // 记录开始时间
        exchange.getAttributes().put("startTime", System.currentTimeMillis());
        exchange.getAttributes().put("requestId", requestId);
        
        return chain.filter(exchange).then(
            Mono.fromRunnable(() -> {
                Long startTime = exchange.getAttribute("startTime");
                if (startTime != null) {
                    long duration = System.currentTimeMillis() - startTime;
                    ServerHttpResponse response = exchange.getResponse();
                    log.info("Gateway Response: {} {} {} - {} in {}ms",
                        requestId,
                        request.getMethod(),
                        request.getPath().pathWithinApplication().value(),
                        response.getStatusCode(),
                        duration
                    );
                }
            })
        );
    }
}

自定义路由过滤器

点击查看完整代码实现
java
@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();
            
            // 添加自定义请求头
            ServerHttpRequest newRequest = request.mutate()
                .header("X-Custom-Header", config.getValue())
                .build();
            
            return chain.filter(exchange.mutate().request(newRequest).build())
                .then(Mono.fromRunnable(() -> {
                    // 处理响应
                    ServerHttpResponse response = exchange.getResponse();
                    response.getHeaders().add("X-Custom-Response", config.getValue());
                }));
        };
    }
    
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("value");
    }
    
    public static class Config {
        private String value;
        
        public String getValue() {
            return value;
        }
        
        public void setValue(String value) {
            this.value = value;
        }
    }
}

高级功能

熔断降级

点击查看完整代码实现
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: hystrix-route
          uri: lb://service
          predicates:
            - Path=/api/hystrix/**
          filters:
            - StripPrefix=2
            - name: CircuitBreaker
              args:
                name: myCircuitBreaker
                fallbackUri: forward:/fallback
                
# Resilience4j配置
resilience4j:
  circuitbreaker:
    instances:
      myCircuitBreaker:
        sliding-window-size: 10
        minimum-number-of-calls: 5
        failure-rate-threshold: 50
        wait-duration-in-open-state: 30000
        permitted-number-of-calls-in-half-open-state: 3
java
@RestController
public class FallbackController {
    
    @RequestMapping("/fallback")
    public Mono<Map<String, Object>> fallback(ServerWebExchange exchange) {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "Service temporarily unavailable");
        result.put("timestamp", Instant.now().toString());
        
        return Mono.just(result);
    }
}

重试机制

点击查看完整代码实现
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: retry-route
          uri: lb://service
          predicates:
            - Path=/api/retry/**
          filters:
            - StripPrefix=2
            - name: Retry
              args:
                retries: 3
                series: SERVER_ERROR
                methods: GET,POST
                backoff:
                  firstBackoff: 10ms
                  maxBackoff: 50ms
                  factor: 2
                  basedOnPreviousValue: false

请求去重

点击查看完整代码实现
java
@Component
public class DedupeGlobalFilter implements GlobalFilter, Ordered {
    
    private final RedisTemplate<String, Object> redisTemplate;
    
    public DedupeGlobalFilter(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        
        // 生成请求唯一标识
        String dedupeKey = generateDedupeKey(request);
        
        return Mono.fromCallable(() -> {
                // 检查是否重复请求
                Boolean exists = redisTemplate.hasKey("dedupe:" + dedupeKey);
                if (Boolean.TRUE.equals(exists)) {
                    return false; // 重复请求
                }
                
                // 设置去重标记,5分钟过期
                redisTemplate.opsForValue().set("dedupe:" + dedupeKey, true, Duration.ofMinutes(5));
                return true; // 非重复请求
            })
            .subscribeOn(Schedulers.boundedElastic())
            .flatMap(isUnique -> {
                if (isUnique) {
                    return chain.filter(exchange);
                } else {
                    // 返回重复请求错误
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.CONFLICT);
                    response.getHeaders().add("Content-Type", "application/json");
                    
                    String body = "{\"code\":409,\"message\":\"Duplicate request\"}";
                    DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
                    return response.writeWith(Mono.just(buffer));
                }
            });
    }
    
    private String generateDedupeKey(ServerHttpRequest request) {
        // 基于用户ID、请求路径、请求参数生成唯一标识
        String userId = request.getHeaders().getFirst("X-User-Id");
        String path = request.getPath().value();
        String queryParams = request.getQueryParams().toString();
        
        return DigestUtils.md5DigestAsHex((userId + path + queryParams).getBytes());
    }
    
    @Override
    public int getOrder() {
        return 100;
    }
}

监控与运维

Actuator监控

yaml
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    gateway:
      enabled: true
  info:
    java:
      enabled: true
java
// 获取路由信息
GET /actuator/gateway/routes

// 获取全局过滤器
GET /actuator/gateway/globalfilters  

// 获取路由过滤器
GET /actuator/gateway/routefilters

// 刷新路由
POST /actuator/gateway/refresh

// 获取特定路由详情
GET /actuator/gateway/routes/{id}

Prometheus指标

yaml
management:
  metrics:
    export:
      prometheus:
        enabled: true
点击查看完整代码实现
java
@Component
public class CustomMetrics {
    
    private final Counter requestCounter;
    private final Timer requestTimer;
    private final Gauge activeConnections;
    
    public CustomMetrics(MeterRegistry meterRegistry) {
        this.requestCounter = Counter.builder("gateway.requests.total")
            .description("Total number of gateway requests")
            .register(meterRegistry);
            
        this.requestTimer = Timer.builder("gateway.requests.duration")
            .description("Gateway request duration")
            .register(meterRegistry);
            
        this.activeConnections = Gauge.builder("gateway.connections.active")
            .description("Active connections")
            .register(meterRegistry, this, CustomMetrics::getActiveConnections);
    }
    
    private double getActiveConnections() {
        // 返回活跃连接数
        return 100.0;
    }
}

动态路由管理

点击查看完整代码实现
java
@RestController
@RequestMapping("/admin/routes")
public class RouteController {
    
    @Autowired
    private InMemoryRouteDefinitionRepository routeDefinitionRepository;
    
    @Autowired
    private ApplicationEventPublisher publisher;
    
    @PostMapping
    public Mono<ResponseEntity<Object>> add(@RequestBody RouteDefinition definition) {
        return routeDefinitionRepository.save(Mono.just(definition))
            .then(Mono.fromRunnable(() -> publisher.publishEvent(new RefreshRoutesEvent(this))))
            .then(Mono.just(ResponseEntity.ok().build()));
    }
    
    @PutMapping("/{id}")
    public Mono<ResponseEntity<Object>> update(@PathVariable String id, @RequestBody RouteDefinition definition) {
        return routeDefinitionRepository.save(Mono.just(definition.toBuilder().id(id).build()))
            .then(Mono.fromRunnable(() -> publisher.publishEvent(new RefreshRoutesEvent(this))))
            .then(Mono.just(ResponseEntity.ok().build()));
    }
    
    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
        return routeDefinitionRepository.delete(Mono.just(id))
            .then(Mono.fromRunnable(() -> publisher.publishEvent(new RefreshRoutesEvent(this))))
            .then(Mono.just(ResponseEntity.ok().build()));
    }
    
    @GetMapping
    public Flux<RouteDefinition> list() {
        return routeDefinitionRepository.getRouteDefinitions();
    }
}

最佳实践

性能优化

  • 合理设置Netty连接池和线程池参数
  • 启用HTTP/2支持提升传输效率
  • 使用缓存减少重复计算和外部调用
  • 监控内存使用避免内存泄漏

安全配置

  • 实现统一的认证授权机制
  • 配置CORS策略控制跨域访问
  • 实现请求限流防止DDoS攻击
  • 过滤恶意请求和敏感信息

可靠性保证

  • 配置熔断降级机制
  • 实现优雅的错误处理
  • 建立健康检查和监控告警
  • 制定故障应急处理流程

运维管理

  • 实现动态路由配置管理
  • 建立全链路日志追踪
  • 配置性能监控和统计分析
  • 定期进行压力测试和性能调优

Spring Cloud Gateway作为新一代的响应式API网关,凭借其出色的性能表现、丰富的功能特性和与Spring生态的完美集成,成为微服务架构中API网关的首选方案。

正在精进