Skip to content

Gateway 网关

一、Gateway 概述

网关职责

┌─────────────────────────────────────────────────────────────────┐
│                        Gateway 网关                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                        路由转发                          │  │
│   │                                                         │  │
│   │   /api/user/**  ──────▶  user-service:8080           │  │
│   │   /api/order/** ──────▶  order-service:8081           │  │
│   │   /api/pay/**   ──────▶  payment-service:8082         │  │
│   │                                                         │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
│   ┌─────────────────────────────────────────────────────────┐  │
│   │                        过滤器链                          │  │
│   │                                                         │  │
│   │   请求 ──▶ 认证 ──▶ 限流 ──▶ 路由 ──▶ 日志 ──▶ 响应     │  │
│   │                                                         │  │
│   └─────────────────────────────────────────────────────────┘  │
│                                                                  │
│   功能:路由转发 / 认证鉴权 / 限流熔断 / 日志监控 / 协议转换        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

WebFlux vs Servlet

┌─────────────────────────────────────────────────────────────────┐
│                    Gateway 基于 WebFlux                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Spring WebFlux = Reactive + Non-Blocking                       │
│                                                                  │
│  ┌──────────────────┐     ┌──────────────────┐                  │
│  │  Spring MVC      │     │   Spring WebFlux  │                  │
│  ├──────────────────┤     ├──────────────────┤                  │
│  │  Servlet API     │     │  Reactive Streams │                  │
│  │  同步阻塞        │     │  异步非阻塞       │                  │
│  │  Tomcat/Jetty    │     │  Netty/Reactor   │                  │
│  │  一请求一线程    │     │  事件驱动         │                  │
│  └──────────────────┘     └──────────────────┘                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

二、快速开始

Maven 依赖

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

基础配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-route
          uri: http://localhost:8080
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1

三、路由配置

完整路由配置

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: http://localhost:8080
          predicates:
            - Path=/api/user/**
            - Method=GET,POST
            - Header=X-Request-Id, \d+
            - Query=name, zhang.*
          filters:
            - StripPrefix=1
          order: 1  # 路由优先级,数字越小优先级越高

Java DSL 配置

java
@Configuration
public class GatewayConfig {
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/user/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .addRequestHeader("X-Gateway", "true")
                )
                .uri("http://localhost:8080")
            )
            .route("order-service", r -> r
                .path("/api/order/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .retry(retry -> retry
                        .retries(3)
                        .statuses(HttpStatus.INTERNAL_SERVER_ERROR)
                    )
                )
                .uri("http://localhost:8081")
            )
            .build();
    }
}

动态路由(Nacos)

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          # 使用 lb:// 前缀启用负载均衡
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1

# 自动从 Nacos 获取 user-service 的实例列表
# 并进行负载均衡

四、断言(Predicate)

常用断言

yaml
spring:
  cloud:
    gateway:
      mvc:
        predicates:
          # 1. Path 路径断言(最常用)
          - Path=/api/user/**
          
          # 2. Method 方法断言
          - Method=GET,POST
          
          # 3. Header 头断言
          - Header=X-Request-Id, \d+
          
          # 4. Query 参数断言
          - Query=name, zhang.*
          
          # 5. Cookie 断言
          - Cookie=session, abc.*
          
          # 6. Host 主机断言
          - Host=**.example.com
          
          # 7. 远程地址断言
          - RemoteAddr=192.168.1.0/24
          
          # 8. 时间断言(用于版本控制)
          - After=2024-01-01T00:00:00+08:00[Asia/Shanghai]
          - Before=2024-12-31T23:59:59+08:00[Asia/Shanghai]
          - Between=2024-01-01T00:00:00+08:00[Asia/Shanghai],2024-12-31T23:59:59+08:00[Asia/Shanghai]

组合断言

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: complex-route
          uri: http://localhost:8080
          predicates:
            # AND 关系:所有条件都满足
            - Path=/api/user/**
            - Method=GET
            - Header=X-Request-Id, \d+

五、过滤器(Filter)

过滤器类型

┌─────────────────────────────────────────────────────────────────┐
│                        Gateway 过滤器                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                   Gateway Filter                         │    │
│  │                                                         │    │
│  │  ┌─────────────────┐      ┌─────────────────┐           │    │
│  │  │  Global Filter  │      │ Route Filter    │           │    │
│  │  │  全局过滤器      │      │ 路由过滤器       │           │    │
│  │  │  所有路由生效    │      │ 指定路由生效     │           │    │
│  │  └─────────────────┘      └─────────────────┘           │    │
│  │                                                         │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
│  执行顺序:                                                      │
│  1. 所有 GatewayFilter 按 order 排序                           │
│  2. 所有 GlobalFilter 按 order 排序                             │
│  3. 组合后的过滤器链顺序执行                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

内置过滤器

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: filter-demo
          uri: http://localhost:8080
          filters:
            # 1. StripPrefix 去除前缀
            - StripPrefix=1
            
            # 2. PrefixPath 添加前缀
            - PrefixPath=/api
            
            # 3. AddRequestHeader 添加请求头
            - AddRequestHeader=X-Gateway, true
            
            # 4. AddRequestParameter 添加请求参数
            - AddRequestParameter=name, zhangsan
            
            # 5. AddResponseHeader 添加响应头
            - AddResponseHeader=X-Response-Gateway, true
            
            # 6. RemoveRequestHeader 移除请求头
            - RemoveRequestHeader=X-Request-Id
            
            # 7. RemoveResponseHeader 移除响应头
            - RemoveResponseHeader=Server
            
            # 8. SetStatus 设置状态码
            - SetStatus=UNAUTHORIZED
            
            # 9. RedirectTo 重定向
            - RedirectTo=302, https://example.com
            
            # 10. Retry 重试
            - name: Retry
              args:
                retries: 3
                statuses: INTERNAL_SERVER_ERROR
                
            # 11. RequestRateLimiter 限流
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

SetStatus 示例

yaml
spring:
  cloud:
    gateway:
      routes:
        - id: auth-route
          uri: http://localhost:8080
          filters:
            # 401 响应
            - SetStatus=401
            
            # 自定义状态码
            - SetStatus=UNAUTHORIZED

六、全局过滤器

自定义全局过滤器

java
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    private final Logger log = LoggerFactory.getLogger(getClass());
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        
        if (StringUtils.isBlank(token)) {
            log.warn("Token is missing");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 验证 token
        if (!validateToken(token)) {
            log.warn("Invalid token");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 验证通过,继续
        return chain.filter(exchange);
    }
    
    @Override
    public int getOrder() {
        return -100;  // 执行顺序,数字越小越先执行
    }
}

常用全局过滤器

java
// 1. LoadBalancerClientFilter(负载均衡)
// 2. NettyRoutingFilter(路由转发)
// 3. WebClientHttpRoutingFilter(响应式路由)
// 4. RouteToRequestUrlFilter(URL 转换)

组合过滤器执行顺序

┌─────────────────────────────────────────────────────────────────┐
│                    过滤器执行顺序                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 所有过滤器按 order 排序                                      │
│  2. 负数 order 的过滤器先执行                                    │
│  3. 执行 pre 过滤器                                              │
│  4. 执行目标服务                                                  │
│  5. 执行 post 过滤器(倒序)                                     │
│                                                                  │
│  示例:                                                         │
│  - GlobalA (order=-1)                                           │
│  - GlobalB (order=0)                                            │
│  - RouteFilter1 (order=1)                                      │
│  - RouteFilter2 (order=2)                                      │
│                                                                  │
│  执行顺序:GlobalA → GlobalB → RouteFilter1 → RouteFilter2      │
│           → RouteFilter2 → RouteFilter1 → GlobalB → GlobalA     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

七、限流

Redis 限流

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: rate-limit-route
          uri: http://localhost:8080
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10      # 每秒允许请求数
                redis-rate-limiter.burstCapacity: 20       # 桶容量
                redis-rate-limiter.requestedTokens: 1      # 每个请求消耗令牌

自定义限流 Key

java
@Component
public class KeyResolver implements KeyResolver {
    
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        // 方式1:按 IP 限流
        String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
        return Mono.just(ip);
        
        // 方式2:按用户限流
        // String userId = exchange.getPrincipal().map(Principal::getName).block();
        // return Mono.just(userId);
        
        // 方式3:按路径限流
        // String path = exchange.getRequest().getPath().value();
        // return Mono.just(path);
    }
}
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: rate-limit-route
          uri: http://localhost:8080
          filters:
            - name: RequestRateLimiter
              args:
                key-resolver: '#{@pathKeyResolver}'  # 引用 Bean
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200

八、CORS 配置

java
@Configuration
public class CorsConfig {
    
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.setAllowCredentials(true);
        config.setMaxAge(3600L);
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(
            new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        
        return new CorsWebFilter(source);
    }
}
yaml
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOriginPatterns: "*"
            allowedHeaders: "*"
            allowedMethods: "*"
            allowCredentials: true
            maxAge: 3600

九、高可用

架构

                    ┌─────────────────┐
                    │     Nginx       │
                    │   (负载均衡)     │
                    └────────┬────────┘

         ┌────────────────────┼────────────────────┐
         │                    │                    │
    ┌────┴────┐          ┌────┴────┐          ┌────┴────┐
    │Gateway-1│          │Gateway-2│          │Gateway-3│
    │ :8080   │          │ :8080   │          │ :8080   │
    └─────────┘          └─────────┘          └─────────┘

Nginx 配置

nginx
upstream gateway {
    server 192.168.1.101:8080;
    server 192.168.1.102:8080;
    server 192.168.1.103:8080;
}

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        proxy_pass http://gateway;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

十、面试高频问题

Q1: Gateway 和 Zuul 区别?

对比ZuulGateway
线程模型同步阻塞响应式非阻塞
技术栈ServletWebFlux
性能一般更高
维护已停止活跃

Q2: 过滤器执行顺序?

  1. 按 order 排序(全局/路由)
  2. 负数先执行
  3. pre → 路由 → post(倒序)

Q3: 如何实现认证?

java
@Component
public class AuthFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(...) {
        // 1. 提取 Token
        // 2. 验证 Token
        // 3. 放行或拒绝
    }
}

Q4: 动态路由如何实现?

配置 lb://service-name,Gateway 会从 Nacos/Eureka 获取服务实例列表并负载均衡

十一、下一章预告

下一章我们将学习 Spring 高级特性

  • 三级缓存与循环依赖
  • Bean 生命周期
  • 动态代理与 AOP 原理
  • 事务传播行为

基于 MIT 许可发布