Skip to content

Spring Cloud Gateway 极简教程


一、基础理论

1. 定位

  • API 网关:微服务架构的统一入口,承担路由转发、负载均衡、协议转换。
  • 横切能力:鉴权、限流、熔断、重写、日志、跨域等集中处理,避免每个服务重复实现。
  • Spring 官方替代 Zuul:基于 Spring 5 + WebFlux + Reactor + Netty,异步非阻塞,性能更高。

2. 核心概念

概念说明
Route路由网关的基本映射单元;由 ID、目标 URI、Predicate、Filter 组成。
Predicate断言断言/匹配条件,决定请求是否进入该 Route(如路径、Header、参数)。
Filter过滤器过滤器,请求/响应在网关流转期间被加工处理(如加 Header、重写路径、限流)。

3. 核心架构与工作原理

  1. Netty Server:底层基于 Netty 接收请求,区别于传统 Servlet Tomcat 阻塞模型。
  2. HandlerMappingRoutePredicateHandlerMapping 遍历所有 Route,用 Predicate 匹配当前请求。
  3. Filter 链:匹配成功后,按 Global Filter → Route Filter → 代理请求 → Route Filter → Global Filter 的顺序执行。
  4. 负载均衡:URI 写成 lb://service-name,配合 ReactiveLoadBalancerClientFilter 从注册中心选择实例。

请求流转拆解

  • 请求 → Netty → Predicate 匹配 → 进入 Filter 链 → LoadBalancer 选实例 → 转发到目标服务。
  • 目标响应后反向经过 Filter 链 → 返回客户端。
  • 全程异步非阻塞,线程数远低于传统阻塞网关。

4. 内置 Predicate 速览

Predicate示例
Path路径匹配,最常用;如 /api/order/**
MethodHTTP 方法匹配,如 GET,POST
Header请求 Header 匹配,支持正则
Query查询参数匹配
After/Before/Between时间窗口匹配
RemoteAddr远端 IP 匹配
Weight按权重分流到不同 Group(灰度/蓝绿)

5. 内置 Filter 速览

Filter作用
AddRequestHeader给转发请求加 Header
AddResponseHeader给响应加 Header
RewritePath重写请求路径
StripPrefix去掉路径前缀(如 /api/order/1/order/1
SetPath直接设置路径
RequestRateLimiter基于 Redis 限流(令牌桶算法)
CircuitBreaker集成 Resilience4j/Spring Cloud Circuit Breaker 熔断
Retry重试机制

6. 与 Zuul 对比

维度Zuul 1.xSpring Cloud Gateway
底层框架Servlet 同步阻塞WebFlux + Netty 异步非阻塞
性能一般,线程开销大更高并发、更低延迟
编程模型阻塞Reactive 响应式
长连接支持WebSocket 友好
官方维护Netflix 维护放缓Spring 官方主推
负载均衡RibbonSpring Cloud LoadBalancer

选型建议:新架构直接选 Gateway;Zuul 2.x 虽异步但 Spring Cloud 未集成。


二、工作实践(复制即用)

1. 基础依赖

最小网关依赖

xml
<dependencies>
    <!-- Gateway 本身 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- 如果网关也需要注册到 Nacos/Eureka,加 discovery -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <!-- 负载均衡器(URI 用 lb:// 时必须引入) -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
</dependencies>

⚠️ Gateway 基于 WebFlux,不要引入 spring-boot-starter-web(Servlet 冲突)。


2. 基础路由配置(YAML)

yaml
server:
  port: 8080

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        # Route ID
        - id: order-service
          # lb:// 表示从注册中心负载均衡到该服务
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            # 去掉前缀 /api,如 /api/order/1 → /order/1
            - StripPrefix=1

        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1

3. 常见 Predicate 组合示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: admin-route
          uri: lb://admin-service
          predicates:
            # 路径 + 方法 + Header
            - Path=/admin/**
            - Method=GET,POST
            - Header=Authorization, Bearer .+

4. 常见 Filter 示例

重写路径 + 加 Header

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/gateway/product/**
          filters:
            # 正则重写:/gateway/product/123 → /product/v2/123
            - RewritePath=/gateway/product/(?<segment>.*), /product/v2/$\{segment}
            # 给下游请求统一加 Header
            - AddRequestHeader=X-Source, gateway
            # 给响应统一加 Header
            - AddResponseHeader=X-Response-By, spring-cloud-gateway

5. 全局过滤器(GlobalFilter)——统一鉴权示例

GlobalFilter 对所有 Route 生效,用于鉴权、日志、透传 TraceId 等横切逻辑。

java
@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("Authorization");

        // 简单校验:放行 /api/public/**
        String path = request.getURI().getPath();
        if (path.startsWith("/api/public/")) {
            return chain.filter(exchange);
        }

        if (StrUtil.isBlank(token)) {
            log.warn("请求缺少 Token,拒绝访问: {}", path);
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            String body = "{\"code\":401,\"message\":\"未登录\"}";
            DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
            return response.writeWith(Mono.just(buffer));
        }

        // 透传 traceId(假设从 MDC 或 Header 中来)
        String traceId = Optional.ofNullable(request.getHeaders().getFirst("X-Trace-Id"))
                .orElse(UUID.fastUUID().toString());

        ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-Trace-Id", traceId)
                .build();

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

    @Override
    public int getOrder() {
        // 数字越小越先执行;鉴权建议放前面
        return -100;
    }
}

6. 自定义 GatewayFilter(局部)

若只想对特定 Route 生效,可自定义 GatewayFilterFactory

java
@Component
public class CustomAuthGatewayFilterFactory
        extends AbstractGatewayFilterFactory<CustomAuthGatewayFilterFactory.Config> {

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 可读取 config.name / config.value 做逻辑
            return chain.filter(exchange);
        };
    }

    @Data
    public static class Config {
        private String name;
        private String value;
    }
}

YAML 中使用

yaml
filters:
  - CustomAuth=name,xxx  # 若不需要参数可简化

7. 跨域配置(CORS)

yaml
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
            allowCredentials: true

8. 集成 Redis 限流(RequestRateLimiter)

增加依赖

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

配置 KeyResolver

java
@Configuration
public class RateLimiterConfig {

    /**
     * 按 IP 限流
     */
    @Bean
    public KeyResolver remoteAddrKeyResolver() {
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
}

YAML 配置

yaml
spring:
  redis:
    host: localhost
    port: 6379
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=1
            # 令牌桶:每秒允许 10 个请求,突发容量 20
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
                key-resolver: "#{@remoteAddrKeyResolver}"

9. 启动类

java
@SpringBootApplication
@EnableDiscoveryClient  // 如需注册到 Nacos/Eureka
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

三、核心速查表

概念/配置说明
Route路由单元:id + uri + predicates + filters
uri: lb://service-name启用负载均衡,需引入 spring-cloud-starter-loadbalancer
Path=/api/**路径断言,最常用
StripPrefix=n去掉前 n 个路径段
RewritePath正则重写路径
AddRequestHeader向下游请求加 Header
RequestRateLimiterRedis 令牌桶限流
GlobalFilter全局过滤器,所有请求生效;实现 Ordered 控制顺序
GatewayFilterFactory局部过滤器工厂,只对配置了该 Filter 的 Route 生效
@EnableDiscoveryClient网关本身注册到注册中心(可选,若不需要服务发现可不加)
spring-cloud-starter-web禁止引入,与 WebFlux 冲突

四、排错速查

现象解决
启动报错 Spring MVC found检查是否引入了 spring-boot-starter-web移除即可
路由不生效 / 4041. 检查 predicates 是否匹配请求路径
2. 检查 uri 是否正确(HTTP 要写全 http://;服务发现用 lb://
StripPrefix 后路径不对确认 StripPrefix 的数字:如 /api/order/1 去 1 段得 /order/1
负载均衡报错 503 / no available1. 确认下游服务已注册到注册中心
2. 确认引入了 spring-cloud-starter-loadbalancer
限流不生效1. 确认 Redis 可用
2. 确认引入了 spring-boot-starter-data-redis-reactive
3. 确认 key-resolver Bean 名称与表达式一致
自定义 Filter 不触发局部 Filter 需写 xxxGatewayFilterFactory 命名;全局 Filter 需实现 GlobalFilter + @Component
响应中文乱码GlobalFilter 中设置 MediaType.APPLICATION_JSON 并指定 UTF-8
WebSocket 转发失败Gateway 原生支持 WS,URI 写成 ws://host:portlb:ws://service-name