Spring Cloud Gateway 从入门到实战

前言

在微服务架构中,前端直接调用众多微服务会面临 IP / 端口硬编码、无法负载均衡、权限无法统一控制 等问题。Spring Cloud Gateway 作为 Spring 官方推出的网关组件,性能远超 Zuul,是微服务生态的统一入口,承担路由转发、权限校验、流量控制、日志监控等核心职责。


一、Gateway 核心介绍

1.1 为什么要用 Gateway?

前端(Vue / 小程序 / App)直接调用微服务存在致命问题:

  1. 客户端维护大量 IP / 端口,硬编码严重
  2. 无法实现负载均衡
  3. 权限、日志、限流无法统一处理
  4. 跨域、安全难以统一管控

引入网关后架构:

复制代码
前端 → Gateway(统一入口) → 微服务集群

1.2 什么是 Spring Cloud Gateway?

Spring Cloud Gateway 是 Spring 官方基于 WebFlux(Reactor+NIO) 开发的新一代网关,用于替代 Zuul,核心功能:

  • 路由转发
  • 断言匹配
  • 过滤器链
  • 限流 / 安全 / 监控

性能对比:Gateway RPS 是 Zuul 1.x 的 1.6 倍

1.3 核心依赖注意

XML 复制代码
<!-- 网关核心依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

⚠️ 严禁引入:spring-boot-starter-webGateway 基于 WebFlux(非阻塞),Web 依赖是 Servlet(阻塞),会冲突导致启动失败。

二、Gateway 工程搭建

2.1 pom.xml

XML 复制代码
<dependencies>
    <!-- Nacos 服务发现 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- Gateway 网关 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

2.2 application.yml

XML 复制代码
server:
  port: 9527

spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.61.132:8848 # Nacos 地址

2.3 启动类

java 复制代码
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
public class ApiGatewayApp {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApp.class, args);
    }
}

三、路由配置(核心)

路由 = ID + URI + Predicates + Filters

3.1 方式一:固定地址路由(硬编码)

java 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: sentinel-consumer # 唯一标识
          uri: http://127.0.0.1:8080 # 固定地址
          predicates:
            - Path=/consumer/** # 路径匹配

3.2 方式二:服务名负载均衡(推荐)

lb:// 表示从 Nacos 获取服务列表,自动负载均衡

java 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: sentinel-consumer
          uri: lb://sentinel-consumer # 服务名
          predicates:
            - Path=/consumer/**

四、断言工厂 Predicates

断言:满足条件才路由,可组合使用。

4.1 常用内置断言工厂

断言 说明
Path=/xxx/** 路径匹配
Method=GET 请求方法匹配
After = 时间 在指定时间之后
Before = 时间 在指定时间之前
Between = 时间,时间 时间区间
RemoteAddr=IP 段 IP 白名单
Header=name,\d+ 请求头匹配
Cookie=name,xxx Cookie 匹配
Query=name,xxx 请求参数匹配

示例:

java 复制代码
predicates:
  - Path=/consumer/**
  - Method=GET
  - After=2024-12-31T23:59:59.999+08:00[Asia/Shanghai]

4.2 自定义断言工厂(实战:年龄判断)

4.2.1 编写断言工厂
java 复制代码
@Component
public class AgeRoutePredicateFactory 
        extends AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {

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

    // 配置文件参数顺序
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("minAge", "maxAge");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            String ageStr = exchange.getRequest().getQueryParams().getFirst("age");
            if (StringUtils.isNotBlank(ageStr)) {
                int age = Integer.parseInt(ageStr);
                return age > config.minAge && age < config.maxAge;
            }
            return false;
        };
    }

    @Data
    public static class Config {
        private int minAge;
        private int maxAge;
    }
}
4.2.2 使用自定义断言
java 复制代码
predicates:
  - Path=/consumer/**
  - Age=18,60 # 年龄在 18~60 之间才放行

五、过滤器 Filter

过滤器用于修改请求 / 响应,分为:

  • 局部过滤器(单个路由)
  • 全局过滤器(所有路由)

5.1 常用内置过滤器

过滤器 作用
StripPrefix=1 去掉路径前缀
AddRequestHeader 添加请求头
AddResponseHeader 添加响应头
RewritePath 重写路径
RequestRateLimiter 限流

示例:去掉前缀

java 复制代码
filters:
  - StripPrefix=1 # 去掉第一层路径

5.2 自定义过滤器工厂(实战:日志耗时)

5.2.1 编写过滤器工厂
java 复制代码
@Component
public class LogGatewayFilterFactory 
        extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {

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

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

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            if (!config.enable) {
                return chain.filter(exchange);
            }
            long start = System.currentTimeMillis();
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                long time = System.currentTimeMillis() - start;
                System.out.println("接口耗时:" + time + "ms");
            }));
        };
    }

    @Data
    public static class Config {
        private boolean enable;
    }
}
5.2.2 使用自定义过滤器
java 复制代码
filters:
  - StripPrefix=1
  - Log=true # 开启耗时日志

六、全局过滤器 GlobalFilter(统一鉴权)

全局过滤器对所有路由生效,常用于:登录校验、黑名单、日志。

6.1 编写登录全局过滤器

java 复制代码
@Component
public class LoginFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取 token
        String token = exchange.getRequest().getQueryParams().getFirst("token");

        if (StringUtils.isBlank(token)) {
            ServerHttpResponse response = exchange.getResponse();
            Map<String, Object> map = new HashMap<>();
            map.put("code", 401);
            map.put("msg", "请先登录");

            byte[] bytes = JSON.toJSONString(map).getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            return response.writeWith(Mono.just(buffer));
        }

        return chain.filter(exchange);
    }

    // 优先级,数字越小越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

6.2 测试

  • 无 token:返回 401 未登录
  • 带 token:正常路由转发

七、常见问题总结

  1. Gateway 不能引入 spring-boot-starter-web
  2. 服务名路由必须加 lb://
  3. 路径匹配尽量使用 /
  4. 过滤器顺序通过 getOrder () 控制
  5. 自定义断言 / 过滤器工厂类名必须以 XxxRoutePredicateFactory / XxxGatewayFilterFactory 结尾

八、本文总结

  1. Gateway 是微服务统一入口,解决硬编码、无负载均衡、无统一管控问题
  2. 路由支持 固定地址服务名负载均衡
  3. 断言用于路由条件匹配
  4. 过滤器用于请求 / 响应增强
  5. 全局过滤器实现统一登录鉴权
相关推荐
StackNoOverflow3 小时前
Spring Cloud Gateway 服务网关详解
gateway
Han.miracle4 小时前
Spring Cloud + Nacos 环境切换与配置管理最佳实践
数据库·spring boot·spring cloud·maven
tsyjjOvO4 小时前
服务网关 Gateway 从入门到精通
gateway
旷世奇才李先生19 小时前
Docker实战:容器化部署与Docker Compose集群管理(附企业级案例)
spring cloud·docker·eureka
卷毛的技术笔记21 小时前
从“拆东墙补西墙”到“最终一致”:分布式事务在Spring Boot/Cloud中的破局之道
java·spring boot·分布式·后端·spring cloud·面试·rocketmq
2601_949816681 天前
springcloud springboot nacos版本对应
spring boot·spring·spring cloud
甜鲸鱼1 天前
JWT过滤器:从单体应用到微服务架构
微服务·架构·gateway·springcloud
notfound40431 天前
解决SpringCloudGateway用户请求超时导致日志未记录情况
java·spring boot·spring·gateway·springcloud
青槿吖1 天前
Sentinel 进阶实战:Feign 整合 + 全局异常 + Nacos 持久化,生产环境直接用
java·开发语言·spring cloud·微服务·云原生·ribbon·sentinel