Article

负载均衡 Spring Cloud Gateway

更新于:2026-07-15

第一章:Spring Cloud Gateway 概述与核心概念

1.1 什么是 Spring Cloud Gateway

Spring Cloud Gateway 是基于 Spring 5、Spring Boot 2 和 Project Reactor 构建的 API 网关。它提供了一种简单而有效的方式来路由到 API 并为它们提供横切关注点,如:安全性、监控/指标和弹性。

1.2 核心概念

| 概念 | 说明 | |: --- | --- | | Route(路由) | 网关的基本构建块,定义了请求匹配规则和转发目标。包含唯一 ID、目标 URI、断言集合、过滤器集合等。 | | Predicate(断言) | 用于匹配 HTTP 请求中的某些属性(如路径、方法、头信息等),决定是否应用该路由。 | | Filter(过滤器) | 在请求被路由前或后修改请求或响应。分为”前置过滤器”和”后置过滤器”。 | | GatewayFilter | 特定于某个路由的过滤器,可链式处理。 | | GlobalFilter | 全局生效的过滤器,对所有路由起作用。 |

第二章:环境搭建与基础配置

2.1 添加依赖与启动类配置

创建 Spring Boot 项目并引入 spring-cloud-starter-gateway 依赖。

Maven 配置示例:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

确保不引入 spring-boot-starter-web,避免与 Netty 冲突。

2.2 基础路由配置方式

支持两种配置方式:Java 代码配置和 YAML 配置。

第三章:路由定义与断言工厂(Route & Predicate Factories)

3.1 RouteLocator 与自定义路由配置

通过 RouteLocatorBuilder 构建路由规则,调用 RouteLocatorBuilder.Builder.route() 方法。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | id | route().id(String id) | 设置路由唯一标识 | id("user-service-route") | 建议命名清晰,便于排查问题 | | path | route().path(String... patterns) | 根据请求路径匹配路由 | path("/user/**") | 支持 Ant 风格路径,如 /**/user/*/info | | uri | route().uri(URI uri)uri(String uri) | 设置目标服务地址 | uri("http://localhost:8081") | 可使用 lb://service-name 实现负载均衡 | | filter | route().filter(GatewayFilter filter, int order) | 添加 GatewayFilter 过滤器 | filter(new CustomFilter(), 1) | order 越小优先级越高 | | filters | route().filters(GatewayFilterSpec spec) | 批量添加过滤器 | filters(f -> f.stripPrefix(1).addRequestHeader("X-Request-Foo", "Bar")) | 常用于链式配置多个过滤器 | | predicate | route().predicate(Predicate predicate) | 自定义断言逻辑 | predicate(exchange -> exchange.getRequest().getHeaders().containsKey("Authorization")) | 高级用法,一般使用内置工厂更方便 | | and | route().and() | 组合多个条件(逻辑与) | path("/api/**").and().method(GET) | 多个条件必须同时满足 | | or | route().or() | 组合多个条件(逻辑或) | path("/admin/**").or().header("X-Admin-Flag") | Reactor 不支持直接 or,需用 .or() 方法 |

3.2 内置断言工厂(Predicate Factories)

Spring Cloud Gateway 提供多种内置断言工厂,均以 xxxRoutePredicateFactory 形式存在。

| 断言工厂 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | Path | path(String... patterns) | 匹配请求路径 | path("/product/**", "/order/**") | 最常用,支持多路径匹配 | | Method | method(HttpMethod... methods) | 匹配 HTTP 方法 | method(GET, POST) | 可指定一个或多个方法类型 | | Header | header(String headerName, String regex) | 匹配请求头是否存在或符合正则 | header("X-Auth-Token", "\\d+") | 第二个参数为可选正则表达式 | | Host | host(String... patterns) | 匹配 Host 请求头 | host("**.example.com") | 支持通配符 *** | | Query | query(String param, String regex) | 匹配查询参数是否存在或值符合正则 | query("name", ".john.") | 如只传参数名,则判断是否存在 | | Cookie | cookie(String name, String regex) | 匹配 Cookie 名称及值 | cookie("JSESSIONID", "\\w+") | 常用于会话识别 | | After | after(ZonedDateTime datetime) | 匹配时间之后的请求 | after(ZonedDateTime.now().plusHours(1)) | 常用于灰度发布 | | Before | before(ZonedDateTime datetime) | 匹配时间之前的请求 | before(ZonedDateTime.parse("2025-01-01T00:00:00Z")) | 结合时钟使用 | | Between | between(ZonedDateTime start, ZonedDateTime end) | 匹配时间区间内的请求 | between(now, now.plusMinutes(10)) | 两个时间点之间有效 | | RemoteAddr | remoteAddr(String... addresses) | 匹配客户端 IP 地址 | remoteAddr("192.168.1.1/24") | 支持 CIDR 格式 |

3.3 使用 YAML 配置路由

| 配置项 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | spring.cloud.gateway.routes.id | id: route1 | 路由唯一标识 | id: product-route | 必须唯一 | | spring.cloud.gateway.routes.uri | uri: http://localhost:8081 | 目标服务地址 | uri: lb://product-service | lb 表示使用负载均衡 | | spring.cloud.gateway.routes.predicates | predicates: - Path=/product/** | 断言规则列表 | predicates: - Path=/api/** - Method=GET | 每个断言占一行,用 - 开头 | | spring.cloud.gateway.routes.filters | filters: - StripPrefix=1 | 过滤器列表 | filters: - AddRequestHeader=X-Trace-ID,12345 | 多个过滤器按顺序执行 | | spring.cloud.gateway.discovery.locator.enabled | true/false | 是否自动创建路由(基于服务发现) | enabled: true | 开启后自动为注册中心服务创建路由 |

YAML 示例:

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
            - Method=GET
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-From, Gateway

第四章:过滤器工厂(GatewayFilter & GlobalFilter)

4.1 内置 GatewayFilter 工厂方法

GatewayFilter 用于在请求被路由前后修改请求或响应。以下为常用内置过滤器工厂的方法。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | AddRequestHeader | AddRequestHeader=headerName, headerValue | 添加请求头 | filters: - AddRequestHeader=X-User-ID, 12345 | 支持占位符,如 %{attributes.foo} | | AddRequestParameter | AddRequestParameter=name, value | 添加查询参数 | filters: - AddRequestParameter=source, gateway | 原请求参数保留,新增参数追加 | | AddResponseHeader | AddResponseHeader=headerName, value | 添加响应头 | filters: - AddResponseHeader=X-Response-Time, %{timestamp} | 可在响应阶段插入自定义信息 | | StripPrefix | StripPrefix=n | 剥离前 n 级路径 | filters: - StripPrefix=1 | 如 /api/user/user 转发到目标服务 | | PrefixPath | PrefixPath=/prefix | 在路径前添加前缀 | filters: - PrefixPath=/v1 | 所有请求路径前自动加 /v1 | | SetPath | SetPath=/newpath/{segment} | 重写请求路径 | filters: - SetPath=/users/{segment} | 支持路径变量提取和重写 | | RewritePath | RewritePath=/oldpath/(?.*), /newpath/${segment} | 重写路径正则匹配部分 | RewritePath=/service/(?.*), /${segment} | 注意转义 $$\{} | | SetStatus | SetStatus=401SetStatus=UNAUTHORIZED | 设置响应状态码 | filters: - SetStatus=403 | 可用于拦截并返回固定状态 | | SetResponseHeader | SetResponseHeader=header, value | 替换响应头(若存在) | filters: - SetResponseHeader=Content-Type, application/json | 若头已存在则覆盖 | | RemoveRequestHeader | RemoveRequestHeader=headerName | 移除指定请求头 | filters: - RemoveRequestHeader=Cookie | 增强安全性,防止敏感头泄露 | | RemoveResponseHeader | RemoveResponseHeader=headerName | 移除响应中的指定头 | filters: - RemoveResponseHeader=Server | 隐藏服务器信息 | | Retry | Retry=3, INTERNAL_ERROR, GATEWAY_TIMEOUT | 请求失败时重试 | filters: - Retry=3, 500, GET | 注意幂等性,避免重复提交 |

4.2 全局过滤器(GlobalFilter)核心方法

GlobalFilter 对所有路由生效,无需配置在具体路由中。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | GlobalFilter.filter | Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) | 定义全局处理逻辑 | public class AuthFilter implements GlobalFilter { ... } | 必须实现接口并注册为 Bean | | ServerWebExchange.getAttributes | Object getAttribute(String key) | 获取上下文属性 | String user = exchange.getAttribute("user"); | 可用于跨过滤器传递数据 | | ServerWebExchange.getRequest | exchange.getRequest() | 获取原始请求对象 | URI uri = exchange.getRequest().getURI(); | 不可变对象,需通过 mutated 构建新请求 | | ServerWebExchange.getResponse | exchange.getResponse() | 获取响应对象 | HttpStatus status = exchange.getResponse().getStatusCode(); | 可设置状态、头信息等 | | GatewayFilterChain.filter | chain.filter(exchange) | 继续执行后续过滤器链 | return chain.filter(exchange); | 必须调用否则请求中断 | | exchange.mutate().request() | 构建新的 ServerHttpRequest | 修改请求头或路径 | .request(req -> req.getHeader("X-Forwarded-For")) | 使用 mutate 模式创建不可变对象副本 | | ResponseDecorator | decorate the response body | 修改响应体内容 | WebFilter 封装方式实现 | 复杂,需结合 DataBuffer 处理流 |

Java 示例:

@Component
public class LoggingGlobalFilter implements GlobalFilter {
    private static final Logger log = LoggerFactory.getLogger(LoggingGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("Request {} : {}", exchange.getRequest().getMethod(), exchange.getRequest().getURI());
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            log.info("Response status: {}", exchange.getResponse().getStatusCode());
        }));
    }
}

4.3 过滤器的执行顺序与优先级

Spring Cloud Gateway 中过滤器按类型和 order 决定执行顺序。

| 类型 | 执行阶段 | 排序依据 | 示例 | 注意事项 | |: --- | --- | --- | --- | --- | | GlobalFilter | 全局作用域 | 实现 Ordered 接口或 @Order 注解 | 自定义鉴权、日志过滤器 | order 值越小越早执行 | | GatewayFilter | 局部作用域 | 配置顺序或 filter(order) 参数 | StripPrefix, AddHeader | 在 route 配置中顺序决定 | | Pre Filters | 路由前执行 | order 升序 | Authentication, Rate Limiting | 修改请求前的操作 | | Post Filters | 路由后执行 | order 降序 | Logging, Header Stripping | 处理响应内容 | | 默认排序规则 | —— | GlobalFilter < GatewayFilter;Pre < Route < Post | —— | Spring 内部使用 Flux 排序机制 |

说明:

  • 所有 Pre 类型过滤器先于路由执行。
  • 所有 Post 类型过滤器在路由完成后执行。
  • 自定义 GlobalFilter 应实现 Ordered 接口以明确顺序。

示例实现:

@Component
@Order(-1)
public class HighPriorityFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 最早执行的全局过滤器
        return chain.filter(exchange);
    }
}

第五章:路由发现与动态网关配置

5.1 基于服务发现的自动路由(DiscoveryClient)

通过集成 Eureka、Nacos 等注册中心,实现自动创建路由。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | spring.cloud.gateway.discovery.locator.enabled | enabled: true | 开启基于服务发现的路由自动创建 | enabled: true | 默认路径为 /serviceId/** | | spring.cloud.gateway.discovery.locator.lowerCaseServiceId | lowerCaseServiceId: true | 将服务 ID 转为小写用于路径匹配 | lowerCaseServiceId: true | 避免大小写不一致导致 404 | | spring.cloud.gateway.discovery.locator.includeExpression | includeExpression: true | 自定义包含服务的表达式 | includeExpression: name != 'gateway' | SpEL 表达式,灵活控制 | | spring.cloud.gateway.discovery.locator.urlExpression | urlExpression: ... | 自定义目标 URL 表达式 | urlExpression: "'http://' + serviceId + ':8080'" | 高级用法,覆盖默认 lb:// | | spring.cloud.gateway.discovery.locator.routeIdPrefix | routeIdPrefix: api- | 为自动生成的路由添加前缀 | routeIdPrefix: svc- | 便于识别和管理 |

YAML 示例:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
          routeIdPrefix: svc-

说明:

  • 启用后,每个注册的服务将自动生成一条路由规则,路径为 /${serviceId}/**,目标为 lb://serviceId
  • 可结合 @LoadBalancerClient 实现更复杂的负载均衡策略。

5.2 动态路由配置:通过 Actuator 端点修改路由

使用 spring-cloud-starter-gateway 提供的 /actuator/gateway/routes 端点实现运行时动态增删改查路由。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | POST /actuator/gateway/routes/{id} | HTTP POST 请求 | 添加或更新指定 ID 的路由 | curl -X POST ... -d '{ "id": "new-route", "uri": "http://example.com", "predicates": [ { "name": "Path", "args": { "pattern": "/test/**" } } ] }' | Content-Type: application/json | | GET /actuator/gateway/routes | HTTP GET 请求 | 获取所有当前路由配置 | curl http://localhost:8080/actuator/gateway/routes | 返回 JSON 数组 | | GET /actuator/gateway/routes/{id} | HTTP GET 请求 | 获取指定 ID 的路由详情 | curl http://localhost:8080/actuator/gateway/routes/user-route | 返回单个路由对象 | | DELETE /actuator/gateway/routes/{id} | HTTP DELETE 请求 | 删除指定 ID 的路由 | curl -X DELETE http://localhost:8080/actuator/gateway/routes/user-route | 删除后立即失效 | | refresh | POST /actuator/gateway/refresh | 刷新路由缓存(重新加载) | curl -X POST http://localhost:8080/actuator/gateway/refresh | 手动触发刷新,适用于配置变更 |

启用配置:

management:
  endpoint:
    gateway:
      enabled: true
  endpoints:
    web:
      exposure:
        include: gateway,refresh

注意事项:

  • 生产环境需对 /actuator 端点进行安全控制(如 Spring Security)。
  • 动态路由不持久化,重启后丢失,需结合配置中心实现持久化。

5.3 自定义 RouteDefinitionLocator 实现动态路由加载

通过实现 RouteDefinitionLocator 接口,从数据库、Redis 或配置中心加载路由配置。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | RouteDefinitionLocator.getRouteDefinitions | Flux<RouteDefinition> getRouteDefinitions() | 提供路由定义流 | return Flux.fromIterable(loadFromDB()); | 必须返回 Flux 流,支持响应式 | | RouteDefinition.setId | routeDefinition.setId("xxx") | 设置路由 ID | routeDef.setId("order-service"); | 必须唯一 | | RouteDefinition.setUri | routeDefinition.setUri(URI uri) | 设置目标地址 | routeDef.setUri(URI.create("lb://order")); | 支持 lb:// 实现负载均衡 | | RouteDefinition.setPredicates | predicates: List<PredicateDefinition> | 设置断言定义列表 | 见下方代码示例 | 每个 PredicateDefinition 包含 name 和 args | | RouteDefinition.setFilters | filters: List<FilterDefinition> | 设置过滤器定义列表 | FilterDefinition filter = new FilterDefinition("StripPrefix=1"); | 语法与 YAML 一致 |

Java 示例:

@Component
public class DatabaseRouteDefinitionLocator implements RouteDefinitionLocator {

    @Autowired
    private RouteConfigService routeConfigService; // 从 DB 加载路由配置

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(routeConfigService.findAll().stream()
            .map(config -> {
                RouteDefinition definition = new RouteDefinition();
                definition.setId(config.getId());
                definition.setUri(URI.create(config.getUri()));
                // 构建 predicates 和 filters...
                return definition;
            }).collect(Collectors.toList()));
    }
}

说明:

  • 结合定时任务或消息监听(如 Redis Pub/Sub),可实现配置变更自动刷新。
  • 推荐与 Nacos、Apollo 等配置中心集成,实现集中管理。

第六章:限流、熔断与安全控制

6.1 基于 Redis 的限流过滤器(RequestRateLimiter)

使用 RequestRateLimiterGatewayFilterFactory 实现网关级限流。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | KeyResolver.resolve | Mono<String> resolve(ServerWebExchange exchange) | 提供限流键(如 IP、用户、URL) | return Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); | 必须注册为 Bean,用于生成限流 key | | redis-rate-limiter.replenishRate | replenishRate: 10 | 每秒补充的令牌数(平均速率) | replenishRate: 5 | 控制请求的平均处理速度 | | redis-rate-limiter.burstCapacity | burstCapacity: 20 | 令牌桶总容量(最大突发流量) | burstCapacity: 10 | 超过此值的请求将被拒绝 | | redis-rate-limiter.requestedTokens | requestedTokens: 1 | 每次请求消耗的令牌数 | requestedTokens: 1 | 默认为 1,可自定义 | | Filter 配置语法 | name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 key-resolver: "#{@ipKeyResolver}" | 配置限流规则 | filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 5 redis-rate-limiter.burstCapacity: 10 key-resolver: "#{@userKeyResolver}" | key-resolver 引用 Spring Bean |

YAML 示例:

spring:
  cloud:
    gateway:
      routes:
        - id: rate-limited-route
          uri: http://localhost:8081
          predicates:
            - Path=/api/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 5
                redis-rate-limiter.burstCapacity: 10
                key-resolver: "#{@ipKeyResolver}"

KeyResolver 示例(按 IP 限流):

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

注意事项:

  • 需引入 spring-boot-starter-data-redis-reactive 依赖。
  • Redis 作为令牌桶状态存储,确保高可用。

6.2 集成 Hystrix 实现熔断与降级

使用 HystrixGatewayFilterFactory 提供服务降级能力。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | fallbackUri | fallbackUri: forward:/fallback | 指定降级时转发的本地 URI | fallbackUri: forward:/service-down | 仅支持 forward 协议 | | execution.isolation.strategy | 设置隔离策略(SEMAPHORE/THREAD) | 在 Hystrix 配置中设置 | hystrix.command.default.execution.isolation.strategy: SEMAPHORE | 推荐 SEMAPHORE 避免线程切换 | | circuitBreaker.enabled | circuitBreaker.enabled: true | 开启熔断器 | 默认开启 | 可关闭用于调试 | | metrics.rollingStats.timeInMilliseconds | 统计窗口时间 | 如 10000(10秒) | 默认 10000ms | 决定滑动窗口大小 | | circuitBreaker.requestVolumeThreshold | 触发熔断的最小请求数 | 如 20 | 默认 20 | 请求量过低不开启熔断 | | circuitBreaker.sleepWindowInMilliseconds | 熔断后等待时间 | 如 5000(5秒) | 默认 5000ms | 之后尝试半开状态 | | circuitBreaker.errorThresholdPercentage | 错误率阈值 | 如 50(50%) | 默认 50% | 超过则熔断 |

YAML 示例:

spring:
  cloud:
    gateway:
      routes:
        - id: hystrix-route
          uri: lb://slow-service
          predicates:
            - Path=/slow/**
          filters:
            - name: Hystrix
              args:
                name: slowCommand
                fallbackUri: forward:/fallback

Fallback 处理:

@RestController
public class FallbackController {
    @GetMapping("/fallback")
    public Mono<Map<String, Object>> fallback() {
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("message", "Service is unavailable, please try later.");
        return Mono.just(result);
    }
}

注意事项:

  • spring-cloud-starter-netflix-hystrix 已进入维护模式,建议评估迁移至 Resilience4j。
  • fallbackUri 必须为 forward: 开头,指向网关内部 Controller。

6.3 安全控制:全局鉴权过滤器

通过 GlobalFilter 实现统一身份认证。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | ServerHttpRequest.getHeaders | exchange.getRequest().getHeaders() | 获取请求头信息 | List<String> auth = headers.get("Authorization"); | 返回不可变列表 | | ServerHttpResponse.setStatusCode | exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED) | 设置响应状态码 | response.setStatusCode(HttpStatus.FORBIDDEN); | 必须在写入前设置 | | ServerHttpResponse.setComplete | exchange.getResponse().setComplete() | 终止请求并返回响应 | return exchange.getResponse().setComplete(); | 阻止后续过滤器执行 | | ServerHttpResponse.writeWith | writeWith(Publisher) | 写入响应体内容 | return response.writeWith(Mono.just(buffer)); | 需手动管理 DataBuffer | | ServerWebExchange.getFormData | exchange.getFormData() | 获取表单数据(POST) | exchange.getFormData().subscribe(data -> ...); | 适用于 application/x-www-form-urlencoded |

Java 示例(JWT 鉴权):

@Component
@Order(-1)
public class AuthGlobalFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String authHeader = request.getHeaders().getFirst("Authorization");

        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String token = authHeader.substring(7);
        if (!JwtUtil.validate(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }
}

注意事项:

  • 鉴权逻辑应尽量轻量,避免阻塞。
  • 敏感服务建议结合 OAuth2、JWT 等标准协议。
  • 可使用 Spring Security Reactive 进行更复杂的安全控制。

第七章:监控、日志与性能优化

7.1 集成 Micrometer 与监控指标(Actuator Metrics)

Spring Cloud Gateway 内置对 Micrometer 的支持,可暴露丰富的监控指标。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | spring.boot.actuator.metrics.web.server.auto-time-requests | auto-time-requests: true | 自动记录 HTTP 请求耗时 | 默认开启 | 生成 timer 类型指标 | | meterRegistry.counter | counter(String name, Iterable tags) | 手动记录事件计数 | registry.counter("gateway.requests.total", "service", "user").increment(); | 用于自定义业务指标 | | meterRegistry.timer | timer(String name, Iterable tags) | 手动记录耗时 | Timer.Sample sample = Timer.start(registry); ... sample.stop(registry.timer("gateway.auth.duration")); | 精确测量某段逻辑耗时 | | GatewayMetricsFilter | 自动注册的 GlobalFilter | 收集路由、过滤器执行指标 | 无需手动配置 | 暴露如 spring.cloud.gateway.requests 等指标 | | GET /actuator/metrics | HTTP GET 请求 | 查询可用指标列表 | curl http://localhost:8080/actuator/metrics | 返回指标名称列表 | | GET /actuator/metrics/{name} | HTTP GET 请求 | 获取指定指标详情 | curl "http://localhost:8080/actuator/metrics/http.server.requests?tag=uri:/user" | 支持 tag 过滤 |

启用配置:

management:
  endpoints:
    web:
      exposure:
        include: metrics,health,info
  metrics:
    tags:
      application: ${spring.application.name}

常用指标:

  • http.server.requests:HTTP 请求统计(含状态码、URI、方法、耗时)
  • spring.cloud.gateway.requests:网关特有指标,如路由匹配、过滤器执行
  • jvm.memory.used:JVM 内存使用
  • reactor.netty.http.client.connections:Netty 连接池状态

注意事项:

  • 结合 Prometheus 抓取指标,使用 Grafana 可视化。
  • 高频指标可能影响性能,合理设置采样率。

7.2 日志记录与调试技巧

通过日志分析网关行为,定位问题。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | LoggingExchangeFilterFunction | 包装其他 Filter | 打印请求/响应头信息 | .filter(new LoggingExchangeFilterFunction()) | 仅用于调试,生产慎用 | | spring.cloud.gateway.httpclient.wiretap | wiretap: true | 开启 Netty 级别 Wiretap 日志 | httpclient: wiretap: true | 输出极详细,性能损耗大 | | ServerWebExchange.getAttributes | getAttributes().put(key, value) | 在过滤器间传递上下文信息 | exchange.getAttributes().put("request-start-time", System.currentTimeMillis()); | 用于计算耗时、追踪 ID 等 | | Logger.debug/info/error | log.debug("msg"), log.info("req: {}", req.getURI()) | 输出自定义日志 | private static final Logger log = LoggerFactory.getLogger(AuthFilter.class); | 建议使用 SLF4J | | reactor.netty.http.client.HttpClient | doOnConnected, doOnRequest 等 | 监听客户端事件 | HttpClient.create().wiretap(true).doOnConnected(conn -> log.info("Connected")) | 高级调试,需理解 Reactor |

YAML 配置示例:

logging:
  level:
    org.springframework.cloud.gateway: DEBUG
    reactor.netty: DEBUG
    org.springframework.http: DEBUG

推荐日志策略:

  • 生产环境:INFO 级别,仅记录关键事件(如鉴权失败、熔断触发)
  • 调试环境:DEBUG 或 TRACE,开启 wiretap 查看完整请求/响应
  • 使用 MDC(Mapped Diagnostic Context)传递 traceId、spanId 实现链路追踪

7.3 性能优化建议与最佳实践

提升网关吞吐量与响应速度。

| 优化项 | 方法 | 说明 | 示例 | 注意事项 | |: --- | --- | --- | --- | --- | | 启用 GZIP 压缩 | spring.cloud.gateway.httpclient.responseTimeout | 减少网络传输体积 | response-timeout: 10s | 需后端服务支持 | | 调整线程模型 | reactor.netty.http.server.accessLog | 优化 Reactor 线程数 | accessLog: true | 默认使用 EventLoop,避免阻塞操作 | | 缓存路由配置 | RouteDefinitionLocator 缓存 | 避免频繁加载路由 | 使用 Caffeine 缓存 DB 查询结果 | 动态刷新时清除缓存 | | 连接池配置 | spring.cloud.gateway.httpclient.pool | 配置 Netty 连接池 | pool: maxConnections: 500 acquireTimeout: 10000 | 根据后端服务能力调整 | | 减少过滤器链 | 合并功能相似的过滤器 | 降低处理开销 | 将多个 Header 操作合并 | 过多过滤器增加延迟 | | 使用 lb:// 协议 | uri: lb://service-name | 利用 Ribbon 或 LoadBalancer | 避免硬编码 IP | 实现服务发现与负载均衡 | | 避免阻塞调用 | 不在 GlobalFilter 中使用 Thread.sleep() | 保持响应式非阻塞 | 使用 Mono.delay() 替代 | 阻塞会破坏 Reactor 模型 |

性能测试建议:

  • 使用 JMeter、Gatling 进行压测,关注 TPS、P99 延迟。
  • 监控 GC 频率与内存使用,避免频繁 Full GC。
  • 分析线程堆栈,排查潜在阻塞点。

第八章:高级特性与自定义组件

8.1 自定义 GatewayFilterFactory

通过继承 AbstractGatewayFilterFactory 实现自定义过滤器工厂,支持配置化使用。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | apply | public GatewayFilter apply(Config config) | 创建并返回 GatewayFilter 实例 | return (exchange, chain) -> { ... }; | 核心逻辑,定义过滤行为 | | shortcutFieldOrder | protected List<String> shortcutFieldOrder() | 定义快捷配置字段顺序 | return Arrays.asList("prefix", "suffix"); | 用于 YAML 简写语法 | | getConfigClass | public Class<Config> getConfigClass() | 返回配置类类型 | return Config.class; | 用于类型安全配置 | | name | getClass().getSimpleName().replace("GatewayFilterFactory", "") | 决定过滤器在 YAML 中的名称 | MyCustom → MyCustom | 命名规范:XxxGatewayFilterFactory | | Config 类定义 | public static class Config { ... } | 封装过滤器参数 | private String prefix; private String suffix; | 提供 getter/setter |

Java 示例(添加前后缀头):

@Component
public class AddPrefixSuffixHeaderGatewayFilterFactory
    extends AbstractGatewayFilterFactory<AddPrefixSuffixHeaderGatewayFilterFactory.Config> {

    public AddPrefixSuffixHeaderGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest().mutate()
                .header("X-Custom", config.prefix + "-value-" + config.suffix)
                .build();
            return chain.filter(exchange.mutate().request(request).build());
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("prefix", "suffix");
    }

    public static class Config {
        private String prefix = "pre";
        private String suffix = "suf";

        // getter and setter
        public String getPrefix() { return prefix; }
        public void setPrefix(String prefix) { this.prefix = prefix; }
        public String getSuffix() { return suffix; }
        public void setSuffix(String suffix) { this.suffix = suffix; }
    }
}

YAML 使用:

filters:
  - AddPrefixSuffixHeader=begin, end  # 快捷语法
  # 或完整语法:
  - name: AddPrefixSuffixHeader
    args:
      prefix: start
      suffix: finish

注意事项:

  • 类名必须以 GatewayFilterFactory 结尾。
  • 注册为 Spring Bean 才能被自动发现。
  • 配置类应设计为不可变或线程安全。

8.2 自定义 GlobalFilter

实现 GlobalFilterOrdered 接口,全局拦截所有请求。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | filter | Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) | 定义全局处理逻辑 | return chain.filter(exchange); | 必须调用 chain.filter() 继续执行 | | getOrder | int getOrder() | 定义执行优先级 | return -1; | 越小越早执行 | | ServerWebExchange.getFormData | exchange.getFormData() | 获取 POST 表单数据 | exchange.getFormData().subscribe(data -> log.info("Form: {}", data)); | 仅适用于 application/x-www-form-urlencoded | | ServerWebExchange.getSession | exchange.getSession() | 获取会话(WebSession) | exchange.getSession().doOnSuccess(session -> session.getAttributes().put("user", "id123")) | 响应式会话操作 | | ServerHttpRequestDecorator | 包装原始请求 | 修改请求体(Body) | new ServerHttpRequestDecorator(req) { ... } | 请求体修改复杂,需重写 getBody() |

Java 示例(请求计数):

@Component
@Order(-2)
public class RequestCounterGlobalFilter implements GlobalFilter, Ordered {
    private final AtomicInteger counter = new AtomicInteger(0);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        int count = counter.incrementAndGet();
        log.info("Total requests processed: {}", count);
        return chain.filter(exchange);
    }

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

注意事项:

  • 避免在 filter 方法中执行阻塞操作。
  • 使用 @Order 或实现 Ordered 接口明确顺序。
  • 可结合 Reactor Context 传递跨阶段数据。

8.3 自定义 PredicateFactory

继承 AbstractRoutePredicateFactory 实现自定义路由匹配逻辑。

| 方法名 | 语法 | 用途 | 代码示例 | 注意事项 | |: --- | --- | --- | --- | --- | | apply | public Predicate<ServerWebExchange> apply(Config config) | 返回断言逻辑 | return exchange -> config.getValue().equals("enabled"); | 决定是否匹配该路由 | | getConfigClass | public Class<Config> getConfigClass() | 返回配置类类型 | return Config.class; | 支持类型安全配置 | | shortcutFieldOrder | protected List<String> shortcutFieldOrder() | 快捷参数顺序 | return Collections.singletonList("value"); | 支持 YAML 简写 | | name | getClass().getSimpleName().replace("RoutePredicateFactory", "") | 决定在 YAML 中的名称 | Custom → Custom | 命名规范:XxxRoutePredicateFactory |

Java 示例(基于请求头值匹配):

@Component
public class HeaderValueRoutePredicateFactory
    extends AbstractRoutePredicateFactory<HeaderValueRoutePredicateFactory.Config> {

    public HeaderValueRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            String header = exchange.getRequest().getHeaders().getFirst(config.headerName);
            return header != null && header.equals(config.expectedValue);
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("headerName", "expectedValue");
    }

    public static class Config {
        private String headerName;
        private String expectedValue;

        // getter and setter
        public String getHeaderName() { return headerName; }
        public void setHeaderName(String headerName) { this.headerName = headerName; }
        public String getExpectedValue() { return expectedValue; }
        public void setExpectedValue(String expectedValue) { this.expectedValue = expectedValue; }
    }
}

YAML 使用:

predicates:
  - HeaderValue=X-Feature, enabled

注意事项:

  • 断言应尽量轻量,避免复杂计算。
  • 可结合缓存提升高频匹配性能。
  • 断言失败时,请求将尝试匹配下一个路由。

第九章:实战案例与架构设计

9.1 多租户网关路由设计

实现基于租户标识(如域名、Header、路径前缀)的动态路由。

| 方法 | 实现方式 | 用途 | 代码/配置示例 | 注意事项 | |: --- | --- | --- | --- | --- | | 基于 Host 路由 | 使用 HostRoutePredicateFactory | 不同域名指向不同服务 | predicates: - Host=*.{tenant}.example.com - Path=/** | 配合 DNS 实现多租户隔离 | | 基于 Header 识别租户 | 自定义 GlobalFilter 提取 tenant-id | 统一通过 Header 传递租户信息 | String tenant = request.getHeaders().getFirst("X-Tenant-ID"); | 需在后续服务中透传 | | 动态 URI 构建 | 在过滤器中修改 uri | 根据租户选择不同集群 | uri: lb://tenant-service-${tenant} | 需结合 ServiceInstanceListSupplier | | 路径前缀区分 | 使用 Path 断言 + StripPrefix | /{tenant}/api → 剥离后转发 | predicates: - Path=/{tenant}/api/** filters: - StripPrefix=2 | 前缀需在路由定义中提取 | | 租户级限流 | KeyResolver 按 tenant 分流 | 不同租户独立限流策略 | KeyResolver: "#{@tenantKeyResolver}" | 结合 Redis 实现分布式计数 |

Java 示例(Host 解析租户):

@Component
public class TenantHostResolverFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String host = exchange.getRequest().getHeaders().getHost().hostString();
        // 解析 tenant.example.com → tenant
        String[] parts = host.split("\\.");
        if (parts.length > 2) {
            String tenant = parts[0];
            exchange.getAttributes().put("tenant", tenant);
        }
        return chain.filter(exchange);
    }
}

YAML 路由示例:

- id: tenant-route
  uri: lb://${exchange.attributes.tenant}-service
  predicates:
    - Host=**.example.com
    - Path=/**
  filters:
    - StripPrefix=1

注意事项:

  • 租户信息应在网关层统一注入上下文,避免下游服务解析。
  • 数据隔离需在服务层配合实现。
  • 考虑租户配置的动态加载与缓存。

9.2 灰度发布与金丝雀部署

通过网关实现新版本服务的渐进式流量切分。

| 方法 | 实现方式 | 用途 | 代码/配置示例 | 注意事项 | |: --- | --- | --- | --- | --- | | 基于 Header 路由 | Predicate 匹配特定 Header | 内部测试人员访问新版本 | predicates: - Header=X-Release, canary | 精准控制,适合小范围测试 | | 基于用户 ID 路由 | 自定义 Predicate 解析用户 | 指定用户群体灰度 | if (userId % 100 < 10) routeToV2(); | 需用户信息,适合登录场景 | | 基于权重分流 | 使用 LoadBalancer 的权重策略 | 按百分比分配流量 | nacos: metadata: weight: 90 | 结合 Nacos 权重配置 | | 时间窗口灰度 | 使用 After/Before 断言 | 特定时间段内启用新版本 | predicates: - After=2025-01-01T00:00:00Z | 适合定时上线 | | 动态路由切换 | 通过 Actuator 动态更新路由 | 运行时调整路由目标 | POST /actuator/gateway/routes/canary-route | 需配合配置中心 |

YAML 示例(Header 控制):

- id: canary-route
  uri: lb://user-service-v2
  predicates:
    - Header=X-Canary, true
    - Path=/user/**
  filters:
    - AddResponseHeader=X-Service-Version, v2

- id: stable-route
  uri: lb://user-service-v1
  predicates:
    - Path=/user/**
  filters:
    - AddResponseHeader=X-Service-Version, v1

Java 示例(用户 ID 哈希):

public class UserIdCanaryPredicateFactory
    extends AbstractRoutePredicateFactory<UserIdCanaryPredicateFactory.Config> {

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            String uid = exchange.getRequest().getHeaders().getFirst("X-User-ID");
            if (uid == null) return false;
            int hash = uid.hashCode() & Integer.MAX_VALUE;
            return hash % 100 < config.percentage; // 百分比灰度
        };
    }

    public static class Config {
        private int percentage = 10; // 默认 10%
        // getter/setter
    }
}

注意事项:

  • 灰度期间需加强监控与日志对比。
  • 避免会话不一致(如登录状态)。
  • 准备快速回滚方案。

9.3 API 网关与微前端集成

将网关作为微前端架构的统一入口,聚合后端服务。

| 方法 | 实现方式 | 用途 | 代码/配置示例 | 注意事项 | |: --- | --- | --- | --- | --- | | 静态资源代理 | 路由到前端资源服务器 | / → index.html, /js/* → js/ | - Path=/, /js/**, /css/** - RewritePath=/, /index.html | 支持 SPA 路由 | | 后端服务聚合 | 多路由规则指向不同微服务 | /api/user → user-service /api/order → order-service | uri: lb://user-service | 统一 API 前缀 | | 请求头统一处理 | GlobalFilter 添加 CORS、安全头 | 允许跨域、X-Frame-Options | response.getHeaders().add("Access-Control-Allow-Origin", "*"); | 生产环境限制 Origin | | 路径重写 | RewritePath 过滤器 | /api/user/1/user/1 | RewritePath=/api/(?.*), /${segment} | 隐藏内部结构 | | 认证统一入口 | 鉴权 Filter 拦截所有 API | JWT 验证、OAuth2 | 拒绝不合法请求 | 静态资源可放行 |

YAML 配置示例:

spring:
  cloud:
    gateway:
      routes:
        # 前端静态资源
        - id: frontend
          uri: http://static-server
          predicates:
            - Path=/, /js/**, /css/**, /img/**
          filters:
            - Name: RewritePath
              args:
                regexp: /
                replacement: /index.html

        # 用户服务
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=2

        # 订单服务
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=2

注意事项:

  • 静态资源建议由 CDN 托管,减轻网关压力。
  • 微前端路由与后端 API 路由清晰分离。
  • 考虑前端资源版本化(如 /v1/index.html)避免缓存问题。

第十章:常见问题排查与生产最佳实践

10.1 常见错误与解决方案

针对生产环境中高频出现的问题提供诊断与修复方案。

| 错误现象 | 可能原因 | 诊断方法 | 解决方案 | 预防措施 | |: --- | --- | --- | --- | --- | | 404 Not Found | 路由未匹配、路径未剥离 | 检查 /actuator/gateway/routes 输出 | 核对 Path 断言与 StripPrefix 配置 | 使用 curl -v 测试路径匹配 | | 500 Internal Error | 后端服务不可达、过滤器异常 | 查看网关日志 ERROR 级别 | 检查服务注册状态、过滤器代码逻辑 | 启用 Hystrix 降级 | | 503 Service Unavailable | 服务实例未注册、健康检查失败 | 检查 Eureka/Nacos 控制台 | 确认服务启动并注册成功 | 配置合理的健康检查路径 | | 请求超时 | 后端响应慢、连接池耗尽 | 启用 wiretap: true 查看 Netty 日志 | 调整 response-timeout、扩大连接池 | 设置合理的超时与熔断策略 | | 内存溢出 (OOM) | 请求体过大、数据缓冲未释放 | 分析堆转储 (Heap Dump) | 限制 max-in-memory-size、避免大文件上传 | 配置请求大小限制 | | 路由不生效 | 配置未加载、YAML 缩进错误 | 检查 application.yml 语法 | 使用在线 YAML 验证器校验 | 启用 @ConfigurationProperties 验证 | | 限流失效 | Redis 连接失败、KeyResolver 返回 null | 检查 Redis 状态、日志输出 | 确保 Redis 可用、KeyResolver 返回有效值 | 添加 Redis 健康检查 | | 循环重定向 | 路由配置错误导致自循环 | 使用 curl -v 观察 Location 头 | 检查 RedirectTo 过滤器目标地址 | 避免路由规则覆盖自身路径 |

诊断工具推荐:

  • curl -v http://gateway/path:查看详细请求/响应头
  • http://localhost:8080/actuator/gateway/routes:验证运行时路由配置
  • http://localhost:8080/actuator/health:检查网关健康状态
  • jstack <pid>:分析线程阻塞
  • jmap -histo <pid>:查看内存对象分布

10.2 生产环境部署最佳实践

确保网关在生产环境中的高可用、安全与可维护性。

| 实践领域 | 最佳实践 | 说明 | 实施建议 | |: --- | --- | --- | --- | | 高可用部署 | 集群部署 + 负载均衡 | 避免单点故障 | 使用 Nginx/LVS 做前置负载,网关实例 ≥ 2 | | 配置管理 | 集成 Nacos/Apollo 配置中心 | 实现配置动态化、版本化 | 路由、限流规则存于配置中心,监听变更 | | 安全加固 | 启用 HTTPS、IP 白名单 | 防止未授权访问 | 使用 Let’s Encrypt 证书,关键端点加 IP 限制 | | 监控告警 | 接入 Prometheus + Grafana + AlertManager | 实时监控核心指标 | 告警规则:5xx 错误率 > 1%、P99 延迟 > 1s | | 日志规范 | 结构化日志 + ELK 收集 | 便于搜索与分析 | 使用 JSON 格式,包含 traceId、requestId | | 版本控制 | 路由配置纳入 Git 管理 | 实现变更追溯 | 配置中心配置也需备份到代码仓库 | | 灰度发布 | 先灰度后全量 | 降低变更风险 | 新路由先对内部流量开放,验证无误再全量 | | 资源隔离 | 关键服务独立路由与限流 | 避免故障扩散 | 核心 API 设置独立限流阈值 | | 定期演练 | 故障注入与熔断测试 | 验证系统韧性 | 模拟服务宕机,观察降级是否生效 |

生产配置示例:

server:
  port: 8080
  ssl:
    enabled: true
    key-store: classpath:gateway.p12
    key-store-password: secret
    key-store-type: PKCS12

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s
        pool:
          max-connections: 1000
          acquire-timeout: 10000
      loadbalancer:
        use443: true

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,gateway
  endpoint:
    health:
      show-details: never # 生产隐藏详情

10.3 性能调优与容量规划

提升网关吞吐量,合理规划资源。

| 优化项 | 调优策略 | 目标 | 工具/方法 | |: --- | --- | --- | --- | | JVM 参数 | 合理设置堆大小、GC 策略 | 减少 GC 停顿 | -Xms2g -Xmx2g -XX:+UseG1GC | | Netty 线程 | 调整 EventLoop 线程数 | 充分利用 CPU | reactor.netty.ioWorkerCount=16 | | 连接池 | 预热连接、设置合理最大值 | 减少连接创建开销 | max-connections: 1000, lease-timeout: 60s | | 缓存策略 | 缓存路由定义、鉴权结果 | 降低后端依赖 | 使用 Caffeine 缓存,TTL 30s | | 请求大小限制 | 设置 max-in-memory-size | 防止 OOM | spring.codec.max-in-memory-size=1MB | | 压力测试 | 模拟真实流量场景 | 验证系统瓶颈 | 使用 JMeter/Gatling 压测,目标 TPS 5000+ | | 横向扩展 | 增加网关实例数量 | 提升整体吞吐 | K8s HPA 基于 CPU/TPS 自动扩缩容 | | CDN 卸载 | 静态资源交由 CDN 处理 | 降低网关负载 | 将 /static/、/assets/ 指向 CDN |

容量评估公式:

所需网关实例数 = (日请求总量 × 峰值系数) / (单实例 QPS × 86400)
  • 假设日请求 1 亿,峰值系数 10,单实例 QPS 1000:
  • 实例数 = (1e8 × 10) / (1000 × 86400) ≈ 11.5 → 至少 12 个实例

结语: Spring Cloud Gateway 作为微服务架构的流量入口,其稳定性与性能至关重要。通过本目录的系统学习,从基础配置到高级定制,再到生产实践,开发者可全面掌握网关的核心能力。建议在实际项目中遵循”小步快跑、持续验证”的原则,逐步应用各项功能,确保架构稳健演进。