下载工作台
Spring Cloud 微服务

Spring Cloud Gateway 网关

试读上半部分 · 解锁后可读全文

第 3 章 · Spring Cloud Gateway 路由、过滤器与限流

本章目标:在 svc-spring-demo 部署 gateway-svc 作为统一入口,对外映射虚构域名 https://api.example.com;掌握 RoutePredicateFilter 三元模型;实现路径转发、请求头透传、全局 CORS;配置基于 RedisRequestRateLimiter 的限流;理解网关与 Nacos 服务发现 lb:// 协议配合。

学时建议:5~6 小时(含 2 小时路由调试与限流压测)

前置spring-cloud-web ch01~ch02spring-boot-web ch07 统一响应;Redis 基础(spring-boot-web ch10 缓存章节)。


3.1 为什么需要 API 网关

客户端若直连 user-svc:8081product-svc:8082,将面临:

问题Gateway 解决方案
多个域名/端口统一 api.example.com
跨域 CORS网关集中配置
鉴权重复全局过滤器校验 Token(进阶)
限流防刷RequestRateLimiter
路由灰度按 Header/权重路由(概念)
  浏览器 / SPA
       │
       ▼
┌──────────────────────────────┐
│  gateway-svc :8080           │
│  https://api.example.com     │
│  Predicates + Filters        │
└──────────┬───────────────────┘
           │ lb://user-svc
           │ lb://product-svc
           │ lb://order-svc
           ▼
    Nacos 服务发现(ch02)
教学占位:api.example.com 本地等价 http://127.0.0.1:8080;禁止暴露真实内网网关地址。

3.2 创建 gateway-svc 模块

3.2.1 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

注意:Gateway 基于 WebFlux,不要与 spring-boot-starter-web(Servlet)混在同一模块,避免冲突。

3.2.2 启动类

@SpringBootApplication
@EnableDiscoveryClient
public class GatewaySvcApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewaySvcApplication.class, args);
    }
}

3.3 路由配置:YAML 方式

gateway-svc-dev.yaml(Nacos 或本地):

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false   # 教学关闭自动路由,显式配置更清晰
      routes:
        - id: route-user
          uri: lb://user-svc
          predicates:
            - Path=/api/v1/users/**, /api/v1/auth/**
          # 下游 Controller 自带 /api/v1 前缀,网关不剥离路径,无需 filters

        - id: route-product
          uri: lb://product-svc
          predicates:
            - Path=/api/v1/products/**
          # 下游 Controller 自带 /api/v1 前缀,网关不剥离路径,无需 filters

        - id: route-order
          uri: lb://order-svc
          predicates:
            - Path=/api/v1/orders/**
          # 下游 Controller 自带 /api/v1 前缀,网关不剥离路径,无需 filters

        - id: route-actuator-deny
          uri: no://op
          predicates:
            - Path=/actuator/**
          filters:
            - SetStatus=403
字段含义
id路由唯一标识
urilb://服务名 从 Nacos 负载均衡
predicates匹配条件,满足则命中
filters命中后执行的转换(可选)
关于路径剥离:上面三条路由都没配 StripPrefix——因为本模块下游服务的 Controller 本身就映射在 /api/v1/ 下,网关应原样透传**。只有当上游路径带网关层前缀、下游不带时,才需要 - StripPrefix=2 之类的剥离;而 StripPrefix=0 是无操作,写出来只是教学噪音。

验证

curl http://127.0.0.1:8080/api/v1/products?page=0&size=5
# 应转发至 product-svc,响应与直连 8082 一致(需 product 已启动并注册)

3.4 Predicate 常用类型

Predicate示例场景
Path/api/v1/orders/**按 URL 路径
MethodGET, POST限制 HTTP 方法
HeaderX-Request-Id, \d+灰度、调试
Queryversion, v2版本参数路由
After / Before时间窗口维护公告期
Hostapi.example.com多域名入口

组合示例:仅 POST 创建订单走 order-svc:

predicates:
  - Path=/api/v1/orders
  - Method=POST

3.5 GatewayFilter 常用类型

Filter作用
StripPrefix=n去掉路径前 n 段
AddRequestHeader向下游添加头,如 X-Gateway-Trace
AddResponseHeader响应头
RewritePath正则改写路径
RequestRateLimiter限流(见 3.7)
CircuitBreaker与 Resilience4j 集成(ch05)

3.5.1 透传用户身份(示意)

网关校验 JWT 后向下游注入 Header(鉴权逻辑见 ch10 OAuth2 资源服务器,此处简化):

filters:
  - AddRequestHeader=X-User-Id, placeholder-from-jwt

下游 order-svc 从 Header 读取 X-User-Id信任边界应在网关与内网之间,外网不可直连业务端口。

3.5.2 全局 CORS

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins:
              - "https://shop-spa.example.com"
              - "http://localhost:5173"
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
              - OPTIONS
            allowedHeaders: "*"
            allowCredentials: true
            maxAge: 3600

3.6 Java 代码配置路由(可选)

@Configuration
public class GatewayRouteConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("route-product-java", r -> r
                .path("/api/v1/products/**")
                .filters(f -> f
                    .addRequestHeader("X-From-Gateway", "svc-spring-demo")
                    .stripPrefix(0))
                .uri("lb://product-svc"))
            .build();
    }
}

YAML 与 Java 二选一或合并;团队规模大时 YAML + Nacos 动态刷新更常见。


3.7 限流:RequestRateLimiter

基于 Redis + Token Bucket(响应式)。

3.7.1 配置类

@Configuration
public class RateLimiterConfig {

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

    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(50, 100); // replenishRate, burstCapacity
    }
}

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。