Spring Cloud Gateway动态路由配置与限流熔断过滤器实战

Spring Cloud Gateway是Spring生态的API网关组件,基于Spring WebFlux和Project Reactor构建,提供路由转发、请求过滤、限流熔断等核心能力。相比Zuul 1.x的Servlet阻塞模型,Gateway采用Netty非阻塞模型,在高并发场景下吞吐量优势显著。本文从路由配置到自定义过滤器,完整演示Spring Cloud Gateway的生产级配置。

Gateway架构与核心组件解析

Spring Cloud Gateway的架构由三个核心组件构成:Route(路由)由ID、目标URI、Predicate断言和Filter过滤器组成;Predicate断言匹配HTTP请求的任意属性(Path、Method、Header、Query参数等),匹配成功则走该路由;Filter过滤器在请求转发前后对请求和响应进行修改处理。

请求处理流程:客户端请求到达Gateway后,GatewayHandlerMapping根据Predicate匹配路由,匹配到的路由经过Filter链处理(pre阶段),然后通过ProxyFilter转发到后端服务,响应返回再经过Filter链(post阶段)返回客户端。

项目搭建与依赖配置

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

路由断言Predicate配置方式

Gateway支持配置文件方式和编程方式定义路由。YAML配置方式直观易维护:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
            - Method=GET,POST
            - Header=X-Request-Source, ^(web|mobile)$
          filters:
            - StripPrefix=2
            - AddResponseHeader=X-Gateway-Version, 1.0

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Query=userId, \d+
          filters:
            - StripPrefix=2

        - id: time-route
          uri: lb://maintenance-service
          predicates:
            - Between=2026-08-15T00:00:00+08:00, 2026-08-15T06:00:00+08:00

lb://前缀表示使用服务发现(如Nacos、Eureka)负载均衡,Gateway通过Spring Cloud LoadBalancer选择后端实例。StripPrefix=2表示转发前去掉URL前两级路径,如/api/users/list变为/list。断言支持组合使用,多个断言间为AND关系。

编程式动态路由与Redis存储

配置文件方式修改路由需要重启网关。生产环境需要运行时动态增删路由,通过RouteLocator编程式定义配合Redis持久化:

@Configuration
public class DynamicRouteConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(2)
                    .requestRateLimiter(config -> config
                        .setRedisRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver())
                    )
                )
                .uri("lb://user-service"))
            .build();
    }

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getHeaders().getFirst("X-User-Id") != null
                ? exchange.getRequest().getHeaders().getFirst("X-User-Id")
                : exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }

    @Bean
    RedisRateLimiter redisRateLimiter() {
        // defaultReplenishRate: 每秒令牌填充数
        // defaultBurstCapacity: 令牌桶容量
        return new RedisRateLimiter(100, 200);
    }
}

运行时动态添加路由通过RouteDefinitionWriter和RouteDefinitionRepository实现,配合Redis持久化路由定义:

@RestController
@RequestMapping("/gateway/routes")
public class RouteController {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    @Autowired
    private RouteDefinitionLocator routeDefinitionLocator;

    @PostMapping
    public Mono addRoute(@RequestBody RouteDefinition definition) {
        return routeDefinitionWriter.save(Mono.just(definition))
            .then(Mono.just("Route added: " + definition.getId()));
    }

    @DeleteMapping("/{id}")
    public Mono deleteRoute(@PathVariable String id) {
        return routeDefinitionWriter.delete(Mono.just(id))
            .then(Mono.just("Route deleted: " + id));
    }
}

限流过滤器与Redis令牌桶算法

RequestRateLimiter过滤器底层使用Redis + Lua脚本实现令牌桶限流算法。令牌桶参数:replenishRate(令牌填充速率,每秒生成多少令牌)和burstCapacity(桶最大容量)。实际QPS上限由两者共同决定——稳定QPS等于replenishRate,突发QPS上限等于burstCapacity。

spring:
  cloud:
    gateway:
      routes:
        - id: api-limited
          uri: lb://backend-service
          predicates:
            - Path=/api/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 50
                redis-rate-limiter.burstCapacity: 100
                key-resolver: "#{@ipKeyResolver}"

KeyResolver决定限流维度——按IP限流、按用户限流、按接口限流。按IP限流的KeyResolver:

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
    );
}

超出限流阈值的请求返回HTTP 429 Too Many Requests。可自定义返回体:

@Bean
public GatewayFilter customRateLimitFilter() {
    return (exchange, chain) -> {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String body = "{\"code\":429,\"message\":\"请求过于频繁,请稍后重试\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    };
}

熔断降级与Resilience4j集成

Gateway集成Resilience4j实现熔断降级,后端服务异常时自动短路返回降级响应:

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

resilience4j:
  circuitbreaker:
    configs:
      default:
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 3
  timelimiter:
    configs:
      default:
        timeoutDuration: 5s

fallbackUri指向网关内的降级处理接口,熔断触发时转发到该接口返回预设响应:

@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Mono> fallback(ServerWebExchange exchange) {
        Map result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "服务暂时不可用,请稍后重试");
        result.put("timestamp", System.currentTimeMillis());
        return Mono.just(result);
    }
}

slidingWindowSize=10表示滑动窗口统计10次调用,failureRateThreshold=50表示失败率达到50%时熔断器打开,waitDurationInOpenState=10s表示熔断打开10秒后进入半开状态试探恢复。timeoutDuration=5s为超时阈值,请求超过5秒未返回视为失败。

全局过滤器与跨域CORS配置

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private static final List WHITE_LIST = List.of(
        "/api/auth/login", "/api/auth/register"
    );

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 白名单放行
        if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }

        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return onError(exchange, "Missing or invalid token", HttpStatus.UNAUTHORIZED);
        }

        // 添加用户信息到请求头,传递给后端服务
        String userId = validateToken(token.substring(7));
        ServerHttpRequest mutatedRequest = request.mutate()
            .header("X-User-Id", userId)
            .build();

        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }

    @Override
    public int getOrder() {
        return -100; // 优先级最高
    }

    private Mono onError(ServerWebExchange exchange, String message, HttpStatus status) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(status);
        return response.setComplete();
    }
}

CORS全局配置:

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOriginPatterns(List.of("*"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-dong-tai-lu-you-pei-zhi-yu-xian-liu-rong/

(0)
小编小编
上一篇 9小时前
下一篇 9小时前

相关推荐

Spring Cloud Gateway动态路由配置与限流熔断过滤器实战

Spring Cloud Gateway是Spring生态的API网关组件,基于Spring WebFlux和Project Reactor构建,提供路由转发、请求过滤、限流熔断等核心能力。相比Zuul 1.x的Servlet阻塞模型,Gateway采用Netty非阻塞模型,在高并发场景下吞吐量优势显著。本文从路由配置到自定义过滤器,完整演示Spring Cloud Gateway的生产级配置。

Gateway架构与核心组件解析

Spring Cloud Gateway的架构由三个核心组件构成:Route(路由)由ID、目标URI、Predicate断言和Filter过滤器组成;Predicate断言匹配HTTP请求的任意属性(Path、Method、Header、Query参数等),匹配成功则走该路由;Filter过滤器在请求转发前后对请求和响应进行修改处理。

请求处理流程:客户端请求到达Gateway后,GatewayHandlerMapping根据Predicate匹配路由,匹配到的路由经过Filter链处理(pre阶段),然后通过ProxyFilter转发到后端服务,响应返回再经过Filter链(post阶段)返回客户端。

项目搭建与依赖配置

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>

路由断言Predicate配置方式

Gateway支持配置文件方式和编程方式定义路由。YAML配置方式直观易维护:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
            - Method=GET,POST
            - Header=X-Request-Source, ^(web|mobile)$
          filters:
            - StripPrefix=2
            - AddResponseHeader=X-Gateway-Version, 1.0

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Query=userId, \d+
          filters:
            - StripPrefix=2

        - id: time-route
          uri: lb://maintenance-service
          predicates:
            - Between=2026-08-15T00:00:00+08:00, 2026-08-15T06:00:00+08:00

lb://前缀表示使用服务发现(如Nacos、Eureka)负载均衡,Gateway通过Spring Cloud LoadBalancer选择后端实例。StripPrefix=2表示转发前去掉URL前两级路径,如/api/users/list变为/list。断言支持组合使用,多个断言间为AND关系。

编程式动态路由与Redis存储

配置文件方式修改路由需要重启网关。生产环境需要运行时动态增删路由,通过RouteLocator编程式定义配合Redis持久化:

@Configuration
public class DynamicRouteConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(2)
                    .requestRateLimiter(config -> config
                        .setRedisRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver())
                    )
                )
                .uri("lb://user-service"))
            .build();
    }

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getHeaders().getFirst("X-User-Id") != null
                ? exchange.getRequest().getHeaders().getFirst("X-User-Id")
                : exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }

    @Bean
    RedisRateLimiter redisRateLimiter() {
        // defaultReplenishRate: 每秒令牌填充数
        // defaultBurstCapacity: 令牌桶容量
        return new RedisRateLimiter(100, 200);
    }
}

运行时动态添加路由通过RouteDefinitionWriter和RouteDefinitionRepository实现,配合Redis持久化路由定义:

@RestController
@RequestMapping("/gateway/routes")
public class RouteController {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;
    @Autowired
    private RouteDefinitionLocator routeDefinitionLocator;

    @PostMapping
    public Mono addRoute(@RequestBody RouteDefinition definition) {
        return routeDefinitionWriter.save(Mono.just(definition))
            .then(Mono.just("Route added: " + definition.getId()));
    }

    @DeleteMapping("/{id}")
    public Mono deleteRoute(@PathVariable String id) {
        return routeDefinitionWriter.delete(Mono.just(id))
            .then(Mono.just("Route deleted: " + id));
    }
}

限流过滤器与Redis令牌桶算法

RequestRateLimiter过滤器底层使用Redis + Lua脚本实现令牌桶限流算法。令牌桶参数:replenishRate(令牌填充速率,每秒生成多少令牌)和burstCapacity(桶最大容量)。实际QPS上限由两者共同决定——稳定QPS等于replenishRate,突发QPS上限等于burstCapacity。

spring:
  cloud:
    gateway:
      routes:
        - id: api-limited
          uri: lb://backend-service
          predicates:
            - Path=/api/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 50
                redis-rate-limiter.burstCapacity: 100
                key-resolver: "#{@ipKeyResolver}"

KeyResolver决定限流维度——按IP限流、按用户限流、按接口限流。按IP限流的KeyResolver:

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
    );
}

超出限流阈值的请求返回HTTP 429 Too Many Requests。可自定义返回体:

@Bean
public GatewayFilter customRateLimitFilter() {
    return (exchange, chain) -> {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String body = "{\"code\":429,\"message\":\"请求过于频繁,请稍后重试\"}";
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    };
}

熔断降级与Resilience4j集成

Gateway集成Resilience4j实现熔断降级,后端服务异常时自动短路返回降级响应:

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

resilience4j:
  circuitbreaker:
    configs:
      default:
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10s
        permittedNumberOfCallsInHalfOpenState: 3
  timelimiter:
    configs:
      default:
        timeoutDuration: 5s

fallbackUri指向网关内的降级处理接口,熔断触发时转发到该接口返回预设响应:

@RestController
public class FallbackController {

    @GetMapping("/fallback")
    public Mono> fallback(ServerWebExchange exchange) {
        Map result = new HashMap<>();
        result.put("code", 503);
        result.put("message", "服务暂时不可用,请稍后重试");
        result.put("timestamp", System.currentTimeMillis());
        return Mono.just(result);
    }
}

slidingWindowSize=10表示滑动窗口统计10次调用,failureRateThreshold=50表示失败率达到50%时熔断器打开,waitDurationInOpenState=10s表示熔断打开10秒后进入半开状态试探恢复。timeoutDuration=5s为超时阈值,请求超过5秒未返回视为失败。

全局过滤器与跨域CORS配置

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private static final List WHITE_LIST = List.of(
        "/api/auth/login", "/api/auth/register"
    );

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 白名单放行
        if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }

        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return onError(exchange, "Missing or invalid token", HttpStatus.UNAUTHORIZED);
        }

        // 添加用户信息到请求头,传递给后端服务
        String userId = validateToken(token.substring(7));
        ServerHttpRequest mutatedRequest = request.mutate()
            .header("X-User-Id", userId)
            .build();

        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }

    @Override
    public int getOrder() {
        return -100; // 优先级最高
    }

    private Mono onError(ServerWebExchange exchange, String message, HttpStatus status) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(status);
        return response.setComplete();
    }
}

CORS全局配置:

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOriginPatterns(List.of("*"));
        config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-dong-tai-lu-you-pei-zhi-yu-xian-liu-rong/

(0)
小编小编
上一篇 9小时前
下一篇 9小时前

相关推荐