大家好,前四篇我们已经搭建了一个“稳定、可运行、可维护”的基础微服务架构:通过Nacos实现服务注册与统一配置,通过OpenFeign实现服务间通信,通过Resilience4j实现熔断降级、杜绝服务雪崩。但此时还有一个关键问题未解决——微服务集群有多个服务(user-service、order-service),每个服务都有自己的访问地址,前端需要记住所有服务的地址才能调用,且缺乏统一的权限校验和流量控制,安全性和可管理性极差。今天就兑现预告,手把手教大家集成Spring Cloud Gateway(微服务统一网关),实现路由转发、权限校验、流量控制三大核心功能,让微服务集群更安全、更易管理,全程实操,新手跟着走就能掌握!
温馨提示:实操前请确认前提(避免踩坑):① 已完成前四篇实操,Nacos服务端、user-service、order-service能正常启动、注册、通信,且order-service已集成Resilience4j;② 版本保持一致:Spring Boot 2.6.13 + Spring Cloud Hoxton.SR12 + Nacos 2.0.7;③ 关闭之前启动的所有服务(Nacos除外),本篇将新建Gateway服务,同时修改原有服务适配网关;④ 重点注意:Gateway不依赖Spring Web,而是依赖Spring WebFlux,集成时不要添加错误依赖。

一、先搞懂:Spring Cloud Gateway到底是什么?解决什么问题?

前四篇我们的调用流程是:前端直接访问user-service(http://localhost:8081)、order-service(http://localhost:8082)的接口,这种方式在实际开发中完全不可行,存在3个核心痛点:

  1. 前端维护成本高:前端需要记住所有微服务的地址和端口,一旦某个服务地址变更,前端必须同步修改,极其繁琐;

  2. 缺乏统一权限校验:每个微服务都要单独编写权限校验代码(比如Token校验),重复开发,且难以统一管理(比如修改校验规则,需要逐个修改所有服务);

  3. 无流量控制:高并发场景下,某个服务可能被大量请求击垮,缺乏统一的流量限制手段,无法保护微服务集群。

而Spring Cloud Gateway,就是微服务集群的“统一入口”(相当于写字楼的门禁+前台),所有前端请求都先经过Gateway,再由Gateway转发到对应的微服务,同时统一实现权限校验、流量控制、日志监控等功能,彻底解决上述痛点。

核心定位(新手必记)

  • 统一入口:所有前端请求都经过Gateway,前端只需记住Gateway的地址,无需记住各个微服务的地址;

  • 路由转发:Gateway根据请求路径,将请求转发到对应的微服务(比如请求/gateway/user转发到user-service,/gateway/order转发到order-service);

  • 核心功能:路由转发(基础)、权限校验(安全)、流量控制(稳定)、日志监控(排查),本篇重点实操前3个核心功能。

补充:为什么不用Zuul?(Gateway的优势)
早期的网关组件是Spring Cloud Zuul,但目前Zuul已被Gateway替代,核心优势的:
① 性能更优:Gateway基于Spring WebFlux(响应式编程),Zuul基于Servlet(阻塞式编程),高并 发场景下Gateway性能远超Zuul;
② 功能更全:原生支持路由转发、权限校验、流量控制,无需额外集成过多组件;
③ 原生适配Spring Cloud:和Nacos、OpenFeign等组件无缝集成,配置简单;
④ 支持异步非阻塞,更适合高并发微服务场景。

二、实操核心:Spring Cloud Gateway集成与三大核心功能实现

本篇实操分为5个核心步骤,循序渐进,贴合前四篇的场景:① 新建Gateway服务(统一网关);② 配置路由转发(基础功能,实现前端通过网关访问微服务);③ 实现统一权限校验(Token校验,拦截非法请求);④ 实现流量控制(限制接口调用频率,保护微服务);⑤ 完整测试所有功能,验证网关生效。

重点说明:我们将新建一个独立的gateway-service(网关服务),不修改原有user-service和order-service的核心代码,仅做少量适配;所有前端请求先访问gateway-service,再由网关转发到对应的微服务。

三、第一步:新建gateway-service(网关服务)

Gateway服务是一个独立的Spring Boot服务,核心是集成Spring Cloud Gateway依赖,配置路由规则,步骤如下:
3.1 创建gateway-service项目

  1. 打开IDEA,新建Project,选择“Spring Initializr”,点击Next;

  2. 配置项目基本信息(和前四篇保持一致):

  • Group:com.example;

  • Artifact:gateway-service;

  • Name:gateway-service;

  • Java Version:8;

点击Next,进入依赖选择界面。

3.2 添加核心依赖(重点!避免添加错误依赖)
在依赖选择界面,搜索并勾选以下3个依赖(Spring Boot版本默认2.6.13,无需修改),严禁添加Spring Web依赖(Gateway依赖WebFlux,添加Spring Web会导致冲突,启动失败):

  1. Spring Cloud Gateway:网关核心依赖,实现路由转发、流量控制等功能;

  2. Nacos Discovery Client:Nacos客户端依赖,让Gateway服务注册到Nacos,同时能从Nacos获取其他微服务的地址(实现动态路由);

  3. Spring Cloud Circuit Breaker Resilience4j:Resilience4j集成依赖,让Gateway支持熔断降级(可选,本篇暂不实操,后续进阶补充);

(易错点提醒:① 误添加Spring Web依赖,导致Gateway启动失败;② 漏加Nacos Discovery Client依赖,导致Gateway无法获取微服务地址,路由转发失败)

点击Next,选择项目保存路径,点击Finish,等待项目初始化完成(第一次创建会下载依赖,耐心等待)。

3.3 配置bootstrap.yml(连接Nacos,加载配置)
和前四篇的微服务一致,Gateway服务也集成Nacos配置中心,将路由规则、权限校验、流量控制的配置统一放在Nacos中,方便动态更新。

操作步骤:

  1. 删除gateway-service中原有的application.properties文件;

  2. 新建bootstrap.yml文件(src/main/resources目录下),添加以下配置:

server:
  port: 8080  # 网关服务端口,前端只需记住这个端口,默认8080(避免和其他服务冲突)

spring:
  application:
    name: gateway-service  # 网关服务名称,注册到Nacos的名称
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # Nacos服务端地址,和之前一致
        username: nacos
        password: nacos
      config:
        server-addr: localhost:8848  # Nacos配置中心地址
        username: nacos
        password: nacos
        file-extension: yml  # 配置文件格式
  profiles:
    active: dev  # 激活开发环境配置

配置说明:网关端口设为8080(默认端口,前端访问更便捷),和user-service(8081)、order-service(8082)区分,避免端口冲突。

3.4 启动Gateway服务,验证注册

  1. 启动Nacos服务端(确保正常运行);

  2. 找到gateway-service的主启动类(GatewayServiceApplication),右键Run启动服务;

  3. 启动成功后,打开Nacos控制台(http://localhost:8848/nacos),进入“服务管理→服务列表”,能看到“gateway-service”已注册成功,状态为“健康”;

(常见问题:启动失败排查2点:① 是否误添加了Spring Web依赖,删除即可;② Nacos服务端未启动,或bootstrap.yml中Nacos地址配置错误)

四、第二步:配置路由转发(核心基础功能)

路由转发是Gateway的基础功能,核心是“配置请求路径与微服务的映射关系”——前端请求某个路径(比如/gateway/user/1),Gateway根据配置,将请求转发到对应的微服务(user-service)。

我们采用“Nacos配置中心配置路由规则”(延续统一配置规范,支持动态更新路由,无需重启网关),步骤如下:

4.1 在Nacos控制台创建gateway-service的配置

  1. 打开Nacos控制台,进入“配置管理→配置列表”,点击“+”号,创建配置;

  2. 配置信息如下(严格按以下内容填写,避免出错):

  • 数据ID:gateway-service-dev.yml(命名规范:服务名称-环境名称.yml,和前四篇一致);

    • 配置格式:YAML;

    • 环境:DEV;

    • 配置内容(核心是routes路由规则,添加到bootstrap.yml配置之后):

server:
  port: 8080

spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        username: nacos
        password: nacos
      config:
        server-addr: localhost:8848
        username: nacos
        password: nacos
        file-extension: yml
    # Gateway路由转发配置(核心)
    gateway:
      routes:
        # 路由1:转发到user-service(用户服务)
        - id: user-service-route  # 路由ID,自定义,唯一即可(建议和服务名称对应)
          uri: lb://user-service  # 转发目标地址,lb=负载均衡,user-service是微服务名称(和Nacos注册名称一致)
          predicates:  # 路由断言(判断请求路径是否匹配当前路由)
            - Path=/gateway/user/**  # 匹配路径:所有以/gateway/user开头的请求,都转发到user-service
          filters:  # 路由过滤器(可选,用于修改请求、响应)
            - StripPrefix=1  # 去掉请求路径的第一个前缀(/gateway),比如请求/gateway/user/1,转发后变为/user/1(匹配user-service的接口路径)
        # 路由2:转发到order-service(订单服务)
        - id: order-service-route
          uri: lb://order-service
          predicates:
            - Path=/gateway/order/**
          filters:
            - StripPrefix=1

  profiles:
    active: dev
  1. 点击“发布”,配置创建成功,Gateway会自动加载最新路由规则(无需重启网关,Nacos动态更新生效)。

4.2 路由配置核心说明(新手必记,避免踩坑)

  1. id:路由唯一标识,自定义,建议和微服务名称对应,方便后续维护;

  2. uri:转发目标地址,格式为lb://服务名称,lb代表负载均衡(后续进阶篇讲解负载均衡),服务名称必须和Nacos中微服务的注册名称一致(user-service、order-service);

  3. predicates(路由断言):核心是“匹配请求路径”,Path=/gateway/user/** 表示“所有以/gateway/user开头的请求”,都会匹配当前路由,转发到对应的微服务;

  4. filters(路由过滤器):StripPrefix=1 是核心过滤器,作用是“去掉请求路径的第一个前缀”——比如前端请求/gateway/user/1,去掉第一个前缀/gateway后,转发路径变为/user/1,正好匹配user-service的接口(/user/{id}),如果不添加该过滤器,转发路径会是/gateway/user/1,user-service没有该接口,会报错。

4.3 测试路由转发功能

  1. 启动所有服务:Nacos服务端 → user-service → order-service → gateway-service;

  2. 测试user-service路由转发:打开浏览器,访问网关路径:http://localhost:8080/gateway/user/1;

预期结果:请求被转发到user-service,返回正常响应:用户ID:1,用户名:testUser-dev,年龄:25;

  1. 测试order-service路由转发:访问http://localhost:8080/gateway/order/create/1;

预期结果:请求被转发到order-service,返回正常响应(订单创建成功+用户信息);

(常见问题:转发失败排查3点:① 路由配置中服务名称和Nacos注册名称不一致;② 未添加StripPrefix=1过滤器,转发路径错误;③ 对应的微服务未启动,或状态不健康)

五、第三步:实现统一权限校验(核心安全功能)

实际开发中,前端请求必须携带Token(身份凭证)才能访问微服务接口,非法请求(未携带Token、Token失效)需要被拦截,不能转发到微服务。Gateway的统一权限校验,就是在请求转发到微服务之前,拦截请求、校验Token,通过则转发,不通过则返回错误提示,无需在每个微服务中单独编写校验代码。

本篇实操“简单Token校验”(模拟实际开发,重点掌握思路),步骤如下:

5.1 编写权限校验过滤器(核心代码)

Gateway的权限校验通过“自定义全局过滤器”实现,全局过滤器会拦截所有经过网关的请求,执行校验逻辑。

操作步骤:

  1. 在gateway-service中,新建filter包(com.example.gatewayservice.filter);

  2. 创建TokenCheckFilter类,实现GlobalFilter和Ordered接口,编写校验逻辑:

package com.example.gatewayservice.filter;

import org.springframework.cloud.gateway.filter.GlobalFilter;
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注解:将过滤器交给Spring管理,使其生效
@Component
public class TokenCheckFilter implements GlobalFilter, Ordered {

    // 核心校验逻辑:拦截所有请求,校验请求头中的Token
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
        // 1. 获取请求头中的Token(实际开发中,Token由前端携带在请求头中,key通常为Authorization)
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        
        // 2. 模拟Token校验逻辑(实际开发中,会调用认证服务校验Token的有效性,比如JWT校验)
        // 这里简化:假设有效Token为"springcloud-token",未携带Token或Token不正确,视为非法请求
        if (token == null || !"springcloud-token".equals(token)) {
            // 3. 非法请求:返回401未授权状态码,提示"Token无效或未携带Token",不转发请求
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        
        // 4. Token校验通过:放行请求,继续转发到对应的微服务
        return chain.filter(exchange);
    }

    // 过滤器执行顺序:返回值越小,执行顺序越靠前(确保权限校验在路由转发之前执行)
    @Override
    public int getOrder() {
        return -1;  // 设为-1,确保在路由转发过滤器之前执行
    }
}

5.2 权限校验逻辑说明

  1. 自定义全局过滤器必须实现GlobalFilter(核心过滤逻辑)和Ordered(过滤器顺序)接口;

  2. filter方法:拦截所有经过网关的请求,获取请求头中的Token,执行校验逻辑;

  3. 模拟校验规则:有效Token为"springcloud-token",未携带Token、Token为空、Token不匹配,均视为非法请求,返回401未授权;

  4. getOrder方法:返回-1,确保权限校验过滤器在路由转发过滤器之前执行(先校验,再转发,避免非法请求到达微服务)。

5.3 测试权限校验功能
测试分为2个场景,验证合法请求和非法请求的处理效果:

场景1:非法请求(未携带Token)

  1. 保持所有服务正常启动;

  2. 打开浏览器,直接访问:http://localhost:8080/gateway/user/1;

  3. 预期结果:被网关拦截,返回401未授权错误(浏览器显示“401 Unauthorized”),请求未转发到user-service。

场景2:合法请求(携带有效Token)

  1. 由于浏览器直接访问无法添加请求头,我们用Postman测试(新手可下载Postman,简单易用);

  2. 打开Postman,创建GET请求,地址:http://localhost:8080/gateway/user/1;

  3. 在请求头中添加Authorization: springcloud-token(key=Authorization,value=springcloud-token);

  4. 发送请求,预期结果:Token校验通过,请求被转发到user-service,返回正常响应。

(进阶补充:实际开发中,Token校验会更复杂,比如通过JWT解析Token、校验Token有效期、获取用户权限等,后续进阶篇会讲解,本篇重点掌握Gateway全局过滤器的用法)

六、第四步:实现流量控制(核心稳定功能)

流量控制(限流)的核心作用:限制某个接口的调用频率,避免高并发场景下,大量请求击垮微服务(比如秒杀场景,大量请求同时访问订单接口,可能导致order-service崩溃)。Gateway集成Resilience4j即可实现流量控制,步骤如下:
6.1 添加流量控制依赖
打开gateway-service的pom.xml文件,添加Resilience4j限流依赖(和order-service的Resilience4j依赖兼容):

<!-- Resilience4j 限流依赖,用于Gateway流量控制 -->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
    <version>1.7.1</version>
</dependency>

<!-- Gateway集成Resilience4j限流依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-circuitbreaker-resilience4j</artifactId>
</dependency>

添加完成后,点击IDEA右侧“Maven→刷新”,下载依赖。

6.2 配置流量控制规则(Nacos配置中心)

  1. 打开Nacos控制台,进入“配置管理→配置列表”,找到gateway-service-dev.yml,点击“编辑”;

  2. 在原有配置基础上,添加Resilience4j限流配置(复制以下内容,添加到配置末尾):

# Resilience4j 流量控制(限流)配置
resilience4j:
  ratelimiter:
    instances:
      # 限流实例名称,自定义,建议和路由ID对应
      user-service-ratelimiter:
        limit-for-period: 5  # 每个周期允许的最大调用次数(5次)
        limit-refresh-period: 10000  # 周期刷新时间(10000毫秒=10秒)
        timeout-duration: 1000  # 限流等待时间,超过1秒未获取到调用权限,返回错误
      order-service-ratelimiter:
        limit-for-period: 3  # 每个周期(10秒)允许调用3次
        limit-refresh-period: 10000
        timeout-duration: 1000
    # 绑定限流实例到路由
    gateway:
      routes:
        - id: user-service-route
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 5
                redis-rate-limiter.burstCapacity: 10
                key-resolver: "#{@userKeyResolver}"  # 限流key解析器(按用户IP限流)
        - id: order-service-route
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 3
                redis-rate-limiter.burstCapacity: 6
                key-resolver: "#{@userKeyResolver}"

# 自定义限流key解析器(按用户IP限流,同一IP在10秒内只能调用对应次数)
spring:
  cloud:
    gateway:
      routes:
        # 保持原有路由配置不变,新增限流过滤器配置(上述已添加)
        - id: user-service-route
          # 原有配置不变...
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                resilience4j.ratelimiter.instances: user-service-ratelimiter
        - id: order-service-route
          # 原有配置不变...
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                resilience4j.ratelimiter.instances: order-service-ratelimiter
  1. 点击“发布”,限流配置生效(无需重启网关)。

6.3 编写限流key解析器(按用户IP限流)
限流需要指定“限流维度”(比如按用户IP、按用户ID),本篇采用“按用户IP限流”(同一IP在10秒内,访问user-service接口最多5次,访问order-service接口最多3次),步骤如下:

  1. 在gateway-service的filter包下,创建IpKeyResolver类:
package com.example.gatewayservice.filter;

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 IpKeyResolver {

    // 定义限流key解析器,按用户IP作为限流key
    @Bean
    public KeyResolver userKeyResolver() {
        // 获取请求的用户IP,作为限流key(同一IP视为同一个用户)
        return exchange -> Mono.just(
            exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
        );
    }
}

6.4 测试流量控制功能

  1. 保持所有服务正常启动,打开Postman,携带有效Token(Authorization: springcloud-token);

  2. 测试user-service限流:快速发送请求http://localhost:8080/gateway/user/1,10秒内发送超过5次;

预期结果:前5次请求成功,第6次及以后请求被限流,返回429 Too Many Requests(请求过于频繁);

  1. 等待10秒(限流周期刷新),再次发送请求,恢复正常,说明限流规则生效;

  2. 同理测试order-service限流:10秒内发送超过3次请求,会被限流,验证功能生效。

七、实操总结与易错点复盘

本篇我们完成了Spring Cloud Gateway的核心实操,实现了路由转发、统一权限校验、流量控制三大核心功能,成功搭建了微服务集群的“统一入口”,核心收获如下:

  1. 核心流程:新建Gateway服务→配置路由转发→实现统一权限校验(全局过滤器)→实现流量控制(Resilience4j)→测试所有功能;

  2. 关键知识点:① Gateway是微服务统一入口,基于WebFlux,不依赖Spring Web;② 路由转发的核心是“路径匹配+微服务映射”,StripPrefix过滤器用于修正转发路径;③ 统一权限校验通过自定义全局过滤器实现,确保先校验、再转发;④ 流量控制通过Resilience4j实现,可按IP、用户ID等维度限流;

  3. 核心价值:前端只需记住网关地址,无需维护所有微服务地址;统一权限校验减少重复开发;流量控制保护微服务集群,避免高并发击垮服务。

新手必看易错点(重点避坑,结合前四篇补充):

  1. 误添加Spring Web依赖:Gateway依赖WebFlux,添加Spring Web会导致冲突,启动失败,务必删除;

  2. 路由转发路径错误:未添加StripPrefix=1过滤器,导致转发路径多了/gateway前缀,微服务无法匹配接口;

  3. 权限过滤器执行顺序错误:getOrder返回值过大,导致权限校验在路由转发之后执行,非法请求被转发到微服务;

  4. 限流配置未绑定路由:限流实例未和路由关联,导致限流规则不生效;

  5. 微服务未注册到Nacos:Gateway无法获取微服务地址,路由转发失败,测试前务必确认所有服务都已注册到Nacos。

八、下一篇预告

前五篇我们已经完成了SpringCloud基础架构的全流程实操:Nacos(注册+配置)、OpenFeign(通信)、Resilience4j(熔断降级)、Spring Cloud Gateway(统一网关),能搭建一个“稳定、安全、可管理”的微服务集群。下一篇将讲解微服务的“问题排查神器”——Sleuth+Zipkin链路追踪,教大家如何快速定位微服务调用链路中的故障(比如接口超时、报错),解决“调用链路长、排查难”的痛点!

如果这篇实操教程对你有帮助,欢迎点赞、收藏、关注,实操过程中遇到任何问题(比如路由转发失败、权限校验不生效、限流不起作用),都可以在评论区留言,我会逐一回复,帮大家解决新手踩坑问题~

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐