一、什么是 Spring Cloud Gateway?

Spring Cloud Gateway 是 Spring 生态专为微服务架构设计的 API 网关,基于 Netty 实现非阻塞响应式编程,核心功能包括:

  • 路由转发:将客户端请求按规则转发到对应微服务
  • 过滤器链:请求转发前后的增强处理(如认证、日志、限流)
  • 负载均衡:集成 Spring Cloud LoadBalancer 实现服务实例动态路由
  • 断言匹配:通过多种规则精确匹配请求

相比传统网关(如 Zuul),Gateway 具有更高的性能和更丰富的功能,是微服务架构的"流量入口"。

二、路由的核心组成

一个完整的 Gateway 路由由四部分构成:

要素说明
ID路由唯一标识(不可重复)
URI目标服务地址(支持 lb://服务名http://ip:port
Predicates路由断言(匹配请求的规则,多断言需同时满足)
Filters过滤器(请求转发前后的处理逻辑)

三、路由配置方式(环境搭建)

1. 引入依赖

<!--网关-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos服务发现依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2. 配置文件方式(推荐)

通过 application.yml 配置,支持动态刷新:

server:
  port: 8080 # 网关端口
spring:
  application:
    name: gateway # 服务名称
  cloud:
    nacos:
      server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 网关路由配置
        # 用户服务路由
        - id: user-service # 路由id,自定义,只要唯一即可
          # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
          uri: lb://userService # 路由的目标地址 lb就是LoadBalance负载均衡,后面跟服务名称
          predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
            - Path=/user/** # 这个是按照路径匹配,只要以/user/开头就符合要求
          filters:
            - StripPrefix=1       # 去掉路径中第一个前缀(/api)
            - AddRequestHeader=X-Service, user  # 添加请求头

        # 订单服务路由
        - id: order-service-route
          uri: http://localhost:8082  # 直接转发到指定地址
          predicates:
            - Path=/orders/**
            - After=2025-10-01T00:00:00+08:00[Asia/Shanghai]  # 时间断言

3. 代码方式配置

通过 RouteLocatorBuilder 编程式定义路由:

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RouteConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                // 产品服务路由
                .route("product-service-route", r -> r
                        .path("/api/products/**")  // 路径断言
                        .filters(f -> f.stripPrefix(1))  // 过滤器
                        .uri("lb://product-service"))  // 目标服务
                .build();
    }
}

四、路由断言详解

断言(Predicate)是请求的"匹配规则",Gateway 内置多种断言工厂,支持组合使用(需同时满足)。

断言类型示例说明
PathPath=/api/**,/v1/**匹配请求路径(支持多路径和通配符 */**
MethodMethod=GET,POST匹配 HTTP 方法(GET/POST/PUT/DELETE 等)
HeaderHeader=X-Request-Id, \d+匹配请求头(值支持正则表达式)
QueryQuery=name, zhangsan匹配请求参数(如 ?name=zhangsan
HostHost=**.example.com匹配请求主机名(如 api.example.com
CookieCookie=sessionId, ^[a-z0-9]+$匹配 Cookie 值(支持正则)
AfterAfter=2025-10-28T12:00:00+08:00[Asia/Shanghai]匹配指定时间之后的请求
BeforeBefore=2025-12-31T23:59:59+08:00[Asia/Shanghai]匹配指定时间之前的请求
BetweenBetween=2025-10-01T00:00:00+08:00[Asia/Shanghai], 2025-12-31T23:59:59+08:00[Asia/Shanghai]匹配时间区间内的请求

组合断言示例

predicates:
  - Path=/api/pay/**
  - Method=POST
  - Header=Content-Type, application/json
  - Query=source, app  # 要求包含 source=app 参数

五、过滤器详解

过滤器用于请求转发的增强处理,按生效范围分为:

  • 局部过滤器:仅对绑定的路由生效
  • 全局过滤器:对所有路由生效

1. 常用内置过滤器

过滤器示例说明
StripPrefixStripPrefix=2去掉路径前 N 级前缀(如 /api/v1/users/users
PrefixPathPrefixPath=/api给路径添加前缀(如 /users/api/users
AddRequestHeaderAddRequestHeader=X-Env, prod添加请求头
AddResponseHeaderAddResponseHeader=X-Gateway, scg添加响应头
SetPathSetPath=/new/{segment}重写路径(使用占位符)
RequestRateLimiter见实战案例基于 Redis 令牌桶的限流
CircuitBreaker见实战案例熔断降级(需结合 Resilience4j)

全局内置过滤器(对所有路由生效):

spring:
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=X-Powered-By, SpringCloudGateway
        - Logging=INFO  # 日志过滤器

2. 自定义局部过滤器(继承 AbstractGatewayFilterFactory)

规范:类名必须以 GatewayFilterFactory 结尾(Spring 自动扫描要求),否则无法在配置文件中引用。

案例:接口版本校验过滤器

需求:通过请求头 X-API-Version 控制访问,仅允许指定版本的请求通过。

步骤 1:实现过滤器
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

// 类名必须以 GatewayFilterFactory 结尾,否则配置文件无法识别
@Component
public class ApiVersionGatewayFilterFactory extends AbstractGatewayFilterFactory<ApiVersionGatewayFilterFactory.Config> {

    // 配置类:存储过滤器参数(允许的版本号)
    public static class Config {
        private String allowedVersion;

        // getter 和 setter
        public String getAllowedVersion() { return allowedVersion; }
        public void setAllowedVersion(String allowedVersion) { this.allowedVersion = allowedVersion; }
    }

    // 构造器:指定配置类类型
    public ApiVersionGatewayFilterFactory() {
        super(Config.class);
    }

    // 定义配置参数的顺序(与 Config 属性对应)
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("allowedVersion");
    }

    // 核心过滤逻辑
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 1. 获取请求头中的版本号
            String requestVersion = exchange.getRequest().getHeaders().getFirst("X-API-Version");
            
            // 2. 校验版本
            if (config.getAllowedVersion().equals(requestVersion)) {
                // 版本匹配,继续执行后续过滤器
                return chain.filter(exchange);
            } else {
                // 版本不匹配,返回 403 禁止访问
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().setComplete();
            }
        };
    }
}
步骤 2:绑定到路由

在配置文件中通过类名前缀引用(去掉 GatewayFilterFactory 后缀):

spring:
  cloud:
    gateway:
      routes:
        - id: user-service-route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            # 引用自定义过滤器(使用前缀 ApiVersion)
            - name: ApiVersion
              args:
                allowedVersion: v2  # 允许 v2 版本访问

3. 自定义全局过滤器(实现 GlobalFilter)

全局过滤器对所有路由生效,需实现 GlobalFilterOrdered 接口,并通过 @Component 注入容器。

案例:Token 认证全局过滤器

需求:所有请求必须携带有效的 Token(请求头 Authorization),否则拒绝访问。

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class TokenAuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
        // 1. 获取请求头中的 Token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        
        // 2. 校验 Token(实际项目需调用认证服务)
        if (token == null || !token.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 3. Token 有效,继续执行
        return chain.filter(exchange);
    }

    /**
     * 执行顺序:数值越小优先级越高
     * 此处设置在响应写入前执行(NettyWriteResponseFilter.ORDER = -1)
     */
    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.ORDER - 1;
    }
}

六、路由优先级与动态配置

1. 路由优先级

当多个路由的断言同时匹配请求时,配置顺序决定优先级(先配置的路由优先匹配)。建议:

  • 精确匹配的路由放在前面
  • 模糊匹配的路由放在后面
routes:
  # 精确匹配优先
  - id: user-detail-route
    uri: lb://user-service
    predicates:
      - Path=/api/users/{id}  # 匹配单个用户查询
  
  # 模糊匹配在后
  - id: user-list-route
    uri: lb://user-service
    predicates:
      - Path=/api/users/**    # 匹配所有用户相关请求

2. 动态路由配置

通过配置中心(如 Nacos、Apollo)实现路由动态更新,无需重启网关:

  1. 在配置中心创建 gateway-routes.yml 存储路由配置
  2. 网关服务引入配置中心依赖并配置地址
  3. 配置中心推送变更后,网关自动刷新路由

七、实战案例:完整配置

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      default-filters:
        - AddResponseHeader=X-Gateway, SpringCloudGateway
        # 全局限流过滤器
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10  # 令牌生成速率(每秒10个)
            redis-rate-limiter.burstCapacity: 20  # 令牌桶容量
            key-resolver: "#{@ipKeyResolver}"     # 按IP限流
        
      routes:
        # 用户服务路由(绑定版本过滤器)
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/v1/users/**
            - Method=GET,POST
          filters:
            - StripPrefix=2  # 去掉 /api/v1 前缀
            - name: ApiVersion
              args:
                allowedVersion: v1
        
        # 订单服务路由(熔断处理)
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/v1/orders/**
            - After=2025-01-01T00:00:00+08:00[Asia/Shanghai]
          filters:
            - StripPrefix=2
            - name: CircuitBreaker
              args:
                name: orderServiceCircuitBreaker
                fallbackUri: forward:/fallback/orders  # 熔断降级地址

配套限流 KeyResolver

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimitConfig {
    // 按客户端IP限流
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
                exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
}

八、调试技巧

  1. 开启 Debug 日志

    logging:
      level:
     org.springframework.cloud.gateway: debug  # 打印路由匹配和过滤器执行日志
  2. 使用 Actuator 端点

    management:
      endpoints:
     web:
       exposure:
         include: gateway, routes  # 暴露网关监控端点

    访问 http://localhost:8080/actuator/gateway/routes 可查看所有路由配置。

九、总结

通过本文,你已掌握:

  • 路由的核心组成与两种配置方式(文件/代码)
  • 断言规则的组合使用(路径、方法、时间等)
  • 内置过滤器的常用场景(路径处理、头信息添加等)
  • 自定义过滤器的实现:

    • 局部过滤器:继承 AbstractGatewayFilterFactory,类名以 GatewayFilterFactory 结尾
    • 全局过滤器:实现 GlobalFilterOrdered 接口
  • 路由优先级与动态配置技巧

合理设计路由和过滤器,能让 Gateway 成为微服务架构的"智能入口",实现请求的高效转发与安全管控。


本文作者:
文章标签:Java指南Spring Cloud服务治理运维
文章标题:Spring Cloud Gateway 网关路由详解:从入门到实战
本文地址:https://www.ducky.vip/archives/gateway.html
版权说明:若无注明,本文皆 iDuckie's Blog 原创,转载请保留文章出处。
最后修改:2024 年 02 月 19 日
如果觉得我的文章对你有用,请随意赞赏