Spring Cloud Gateway微服务网关配置:路由转发与限流熔断

微服务API网关的职责与选型

微服务架构中,API网关是所有外部请求的统一入口,承担路由转发、认证鉴权、限流熔断、日志监控等职责。Spring Cloud Gateway基于Spring WebFlux构建,采用非阻塞响应式编程模型,在高并发设计场景下性能优于基于Servlet的传统网关方案。服务治理体系中,网关层是流量控制和安全防护的第一道防线。

Spring Cloud Gateway核心概念与路由配置

Gateway的核心概念包括Route(路由)、Predicate(断言)、Filter(过滤器)。路由由ID、目标URI、断言和过滤器组成,断言匹配请求条件,过滤器修改请求或响应。

# application.yml 路由配置
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
            - Method=GET,POST
          filters:
            - StripPrefix=2
            - AddRequestHeader=X-Gateway,scg

        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Header=Authorization, .+
          filters:
            - StripPrefix=2
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

        - id: payment-service
          uri: lb://payment-service
          predicates:
            - Path=/api/payments/**
            - Host=pay.example.com
          filters:
            - StripPrefix=2

lb://前缀表示使用负载均衡,通过服务注册发现(如Nacos/Eureka)获取后端实例。StripPrefix=2表示去掉URL前两级路径,如/api/users/123转发到/users/123。Predicates支持Path、Method、Header、Host、Query、Cookie等多种匹配方式,可组合使用。

自定义全局过滤器实现认证鉴权

Gateway的全局过滤器对所有路由生效,适合实现JWT认证、日志记录等通用逻辑:

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String[] WHITE_LIST = {
        "/api/auth/login",
        "/api/auth/register",
        "/api/public/**"
    };

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

        // 白名单放行
        for (String pattern : WHITE_LIST) {
            if (path.matches(pattern.replace("**", ".*"))) {
                return chain.filter(exchange);
            }
        }

        // 获取Token
        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return unauthorized(exchange, "Missing or invalid token");
        }

        token = token.substring(7);
        try {
            // 验证Token
            String userId = validateToken(token);
            if (userId == null) {
                return unauthorized(exchange, "Invalid or expired token");
            }

            // 将用户ID传递给下游服务
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", userId)
                .build();

            return chain.filter(exchange.mutate().request(mutatedRequest).build());
        } catch (Exception e) {
            return unauthorized(exchange, "Token validation failed");
        }
    }

    private String validateToken(String token) {
        String userId = redisTemplate.opsForValue().get("token:" + token);
        if (userId != null) {
            // 续期Token
            redisTemplate.expire("token:" + token, 30, TimeUnit.MINUTES);
        }
        return userId;
    }

    private Mono unauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String body = "{\"code\":401,\"message\":\"" + message + "\"}";
        DataBuffer buffer = response.bufferFactory()
            .wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }

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

RequestRateLimiter限流配置与自定义限流策略

Gateway内置的RequestRateLimiter基于Redis令牌桶算法实现限流。配置方式已在路由配置中展示,底层依赖spring-boot-starter-data-redis-reactive:

<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-gateway</artifactId>
</dependency>

内置限流器按IP维度限流,如需按用户或API维度限流,可自定义KeyResolver:

@Configuration
public class RateLimiterConfig {

    @Bean
    public KeyResolver userKeyResolver() {
        // 按用户ID限流
        return exchange -> {
            String userId = exchange.getRequest().getHeaders()
                .getFirst("X-User-Id");
            return Mono.just(userId != null ? userId : "anonymous");
        };
    }

    @Bean
    public KeyResolver apiKeyResolver() {
        // 按API路径限流
        return exchange -> Mono.just(
            exchange.getRequest().getURI().getPath()
        );
    }

    @Bean
    @Primary
    public KeyResolver compositeKeyResolver() {
        // 组合限流: 用户+API
        return exchange -> {
            String userId = exchange.getRequest().getHeaders()
                .getFirst("X-User-Id");
            String path = exchange.getRequest().getURI().getPath();
            return Mono.just(userId + ":" + path);
        };
    }
}

熔断降级与Sentinel集成

Gateway可通过集成Alibaba Sentinel实现更精细的熔断降级控制。Sentinel支持慢调用比例、异常比例、异常数等多种熔断策略:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>
@Configuration
public class GatewayConfig {

    private final List viewResolvers;

    public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(() -> new ArrayList<>());
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers);
    }

    @Bean
    @Order(-1)
    public GatewayFilter sentinelGatewayFilter() {
        return (exchange, chain) -> {
            // 自定义限流降级处理
            return chain.filter(exchange)
                .onErrorResume(ex -> {
                    if (ex instanceof BlockException) {
                        return handleBlocked(exchange);
                    }
                    return Mono.error(ex);
                });
        };
    }

    private Mono<Void> handleBlocked(ServerWebExchange exchange) {
        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(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
}

// 自定义限流规则
@PostConstruct
public void initRules() {
    // 用户服务: QPS限制100,超过则限流
    FlowRule userRule = new FlowRule("user-service");
    userRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    userRule.setCount(100);

    // 订单服务: 线程数限制50
    FlowRule orderRule = new FlowRule("order-service");
    orderRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
    orderRule.setCount(50);

    // 熔断规则: 慢调用比例
    DegradeRule degradeRule = new DegradeRule("payment-service");
    degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
    degradeRule.setCount(500);       // 慢调用阈值500ms
    degradeRule.setSlowRatioThreshold(0.5);  // 慢调用比例>50%
    degradeRule.setTimeWindow(10);    // 熔断10秒

    List<FlowRule> rules = Arrays.asList(userRule, orderRule);
    FlowRuleManager.loadRules(rules);
    DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
}

Sentinel的网关限流规则支持路由ID维度和API分组维度两种限流模式。路由ID维度针对单个路由限流,API分组维度可对多个路由组合限流。熔断规则中的慢调用比例策略在支付等对延迟敏感的场景中尤为重要——当50%以上的请求响应时间超过500ms时触发熔断,10秒后自动恢复探测。API接口规范中应明确定义各服务的SLA指标,并据此配置网关层的限流和熔断参数。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springcloudgateway-wei-fu-wu-wang-guan-pei-zhi-lu-you-zhuan/

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

相关推荐