微服务API网关搭建:Spring Cloud Gateway路由与限流配置

Spring Cloud Gateway架构与路由配置

微服务架构中API网关是所有外部请求的统一入口,负责路由转发、认证鉴权、限流熔断和日志审计。Spring Cloud Gateway基于Spring WebFlux构建,采用响应式编程模型,相比传统Servlet架构的Zuul具有更高的并发吞吐能力。

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

# application.yml 路由配置

spring:
  cloud:
    gateway:
      routes:
        # 用户服务路由
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
            - Method=GET,POST
          filters:
            - StripPrefix=2
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
        
        # 订单服务路由
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Header=Authorization, Bearer .*
          filters:
            - StripPrefix=2
            - AddResponseHeader=X-Gateway-Version, 2.1.0

lb://前缀表示使用负载均衡,Gateway通过服务发现组件(Nacos/Eureka)解析服务名到实际实例地址。StripPrefix=2移除URL前两段路径(/api/users),转发给后端的路径为/users。

自定义过滤器与请求拦截

Gateway提供两种过滤器:Global Filter全局生效,Gateway Filter绑定到特定路由。实际项目中通常通过自定义Global Filter实现认证鉴权、请求日志和跨域处理。

@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private JwtUtil jwtUtil;

    private static final List<String> WHITELIST = List.of(
        "/api/auth/login",
        "/api/auth/register",
        "/api/auth/refresh"
    );

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

        if (WHITELIST.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }

        String auth = request.getHeaders().getFirst("Authorization");
        if (auth == null || !auth.startsWith("Bearer ")) {
            return unauthorizedResponse(exchange, "Missing or invalid Authorization header");
        }

        String token = auth.substring(7);
        try {
            Claims claims = jwtUtil.parseToken(token);
            String userId = claims.getSubject();
            
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", userId)
                .header("X-User-Role", claims.get("role", String.class))
                .build();
            
            return chain.filter(exchange.mutate().request(mutatedRequest).build());
        } catch (Exception e) {
            return unauthorizedResponse(exchange, "Invalid or expired token");
        }
    }

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

    @Override
    public int getOrder() {
        return -100;
    }
}

getOrder()返回值决定过滤器执行顺序,认证过滤器应设置为高优先级(负数),在限流和日志过滤器之前执行。请求修改通过exchange.mutate()创建新的ServerWebExchange,避免直接修改原始请求对象导致的线程安全问题。

限流策略与熔断配置

高并发设计场景下限流是保护后端服务的关键手段。Gateway内置RequestRateLimiter过滤器,基于Redis令牌桶算法实现分布式限流。令牌桶以固定速率生成令牌,请求消耗令牌,桶满时拒绝新请求。

// 自定义限流KeyResolver - 按用户ID限流
@Configuration
public class RateLimiterConfig {

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

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

// Resilience4j熔断配置
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory -> factory.configureDefault(id -> 
        new Resilience4JConfigBuilder(id)
            .timeLimiterConfig(TimeLimiterConfig.custom()
                .timeoutDuration(Duration.ofSeconds(3))
                .build())
            .circuitBreakerConfig(CircuitBreakerConfig.custom()
                .failureRateThreshold(50)
                .slowCallRateThreshold(60)
                .waitDurationInOpenState(Duration.ofSeconds(30))
                .slidingWindowSize(10)
                .minimumNumberOfCalls(5)
                .build())
            .build()
    );
}

熔断器的三个状态:Closed(正常)、Open(熔断,拒绝所有请求)、Half-Open(半开,允许少量请求探测恢复)。failureRateThreshold设为50%意味着10次请求中5次失败即触发熔断,waitDurationInOpenState设为30秒表示熔断30秒后进入半开状态。fallbackUri指定熔断后的降级处理路径,返回缓存数据或友好错误提示。

服务治理与动态路由

生产环境需要动态调整路由规则而不重启Gateway。通过Nacos配置中心实现路由动态刷新:

@Component
public class DynamicRouteListener {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    @NacosConfigListener(dataId = "gateway-routes.json", groupId = "GATEWAY_GROUP")
    public void onRouteChange(String config) {
        List<RouteDefinition> routes = JSON.parseObject(
            config, new TypeReference<List<RouteDefinition>>() {}
        );
        
        routes.forEach(route -> {
            routeDefinitionWriter.delete(Mono.just(route.getId()));
            routeDefinitionWriter.save(Mono.just(route));
        });
        
        ApplicationContextHolder.getContext()
            .publishEvent(new RefreshRoutesEvent(this));
    }
}

动态路由在灰度发布场景中特别有用:新增一条指向新版本服务的路由,通过Header或Cookie匹配将部分流量导入新版本,验证无误后逐步扩大流量比例,实现平滑升级。routeDefinitionWriter是Gateway提供的路由写入接口,配合RefreshRoutesEvent触发路由表刷新,整个过程无需重启服务。

API网关作为微服务架构的流量枢纽,配置复杂度随着服务数量增长而上升。建议将路由配置、限流规则和熔断参数统一存储在配置中心,通过版本管理追踪变更历史。Gateway的JVM参数建议设置-Xmx512m -XX:MaxDirectMemorySize=256m,WebFlux的Netty使用直接内存处理请求,需要单独配置堆外内存上限。

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

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

相关推荐