当前位置: 首页 > news >正文

Spring Cloud 服务网关 Gateway 详解:微服务的 “统一入口” 实战

Spring Cloud 服务网关 Gateway 详解:微服务的 “统一入口” 实战(我们的学习指南)

        结合我们之前学的 Nacos 服务注册、LoadBalancer 负载均衡、OpenFeign 服务调用,今天我们要学的Gateway是微服务架构的 “最后一块拼图”—— 它就像微服务的 “前台接待员”,所有客户端请求都先经过它,由它统一处理路由、鉴权、限流,解决我们之前直接调用服务时的 “地址难记、跨域麻烦、认证分散” 等问题。下面我们从 “为什么需要”“是什么”“怎么实现” 一步步拆解,全程结合我们熟悉的 ServiceOne、ServiceThree 等案例,帮我们建立完整的微服务链路认知。

1. 先想清楚:我们为什么需要服务网关?

在没学 Gateway 之前,我们调用微服务是这样的:

  • 调用 ServiceOne 要访问http://localhost:8001/serviceOne

  • 调用 ServiceThree 要访问http://localhost:8003/serviceThree_toOne

  • 客户端(比如前端)要记很多服务的 IP 和端口,一旦服务地址变了,前端也要跟着改。

除此之外,我们还会遇到 3 个头疼的问题:

  1. 跨域问题:如果前端部署在http://localhost:8080,调用 8001、8003 端口的服务时,会因为浏览器的 “同源策略” 报跨域错误;

  2. 认证分散:每个服务都要写一套登录验证逻辑(比如判断 token 是否有效),重复开发且不好维护;

  3. 监控困难:要统计每个服务的调用量、响应时间,得在每个服务里加监控代码,非常繁琐。

Gateway 的出现就是为了解决这些问题—— 它是客户端和微服务之间的 “中间层”,所有请求都先过 Gateway,由它统一做这些 “非业务工作”:

  • 客户端只需要记 Gateway 的地址(比如http://localhost:8088),不用记所有服务的地址;

  • Gateway 统一处理跨域、认证,服务里不用再写重复逻辑;

  • Gateway 统一收集监控数据,不用每个服务单独配置。

生活类比:我们去医院看病,不用直接找内科、外科医生(对应微服务),而是先去 “前台”(对应 Gateway),前台会问清需求,指引我们去对应科室,还会核对我们的挂号信息(对应鉴权)—— 前台就是医院的 “网关”。

2. Gateway 是什么?和 Zuul 有什么区别?

        在学 Gateway 之前,我们得先知道它的定位:Spring Cloud 官方推出的服务网关,用来替代停更的 Netflix Zuul,专门解决微服务的 “统一入口” 问题。

2.1 先搞懂:Gateway 和 Zuul 的核心区别(我们为什么选 Gateway)

文档里对比了两者,我们用表格更直观地梳理,重点看我们关心的 “性能”“兼容性”“功能”:

对比维度Netflix Zuul(第一代网关)Spring Cloud Gateway(现在用的)
底层实现基于 Servlet,阻塞式 IO基于 Spring WebFlux(Netty),非阻塞式 IO
性能一般(阻塞 IO 处理慢,高并发下容易卡)优秀(非阻塞 IO,支持长连接如 WebSockets)
功能支持需依赖 Hystrix 实现限流、熔断,自身功能少内置限流、负载均衡、路由,不用额外集成
兼容性支持非 Spring Cloud 服务,但配置复杂只适配 Spring Cloud,但和我们的 Nacos、OpenFeign 无缝集成
依赖冲突风险无特殊依赖,但停更后无新功能不能和spring-boot-starter-web(MVC)共存,容易冲突

我们的选择理由

  • 我们用的是 Spring Cloud Alibaba 生态(Nacos、OpenFeign),Gateway 和它们兼容性更好;

  • 我们之前学的 LoadBalancer 负载均衡,Gateway 默认集成,不用额外配置;

  • Zuul 已经停更,遇到 bug 没人修,Gateway 是官方主推,后续有新功能支持。

2.2 Gateway 的核心概念:3 个组件搞定路由

        Gateway 最核心的功能是 “路由转发”—— 把客户端请求转发到对应的微服务,而实现这个功能需要 3 个核心组件,我们得先理解它们:

核心组件我们的通俗理解作用案例
Route(路由)一条 “转发规则”,比如 “请求/one/**就转发到 service-one”我们配置 “/one/**→service-one”,就是一条 Route
Predicate(断言)路由的 “匹配条件”,判断请求是否符合这条 Route比如 “请求路径是/one/**吗?”“请求方法是 GET 吗?”,符合才转发
Filter(过滤器)对请求 / 响应的 “拦截处理”,比如去掉路径前缀、加请求头我们请求/one/serviceOne时,Filter 去掉/one前缀,实际转发到 service-one 的/serviceOne

举个例子帮我们理解:如果我们配置了一条 Route:

  • Route ID:service-one-route(唯一标识);

  • 目标地址:lb://service-one(lb 表示负载均衡,转发到 service-one 服务);

  • Predicate:Path=/one/**(请求路径以/one/开头);

  • Filter:StripPrefix=1(去掉路径的第一个前缀,比如/one/serviceOne变成/serviceOne);

当客户端发请求http://localhost:8088/one/serviceOne时:

  1. Predicate 判断:路径是/one/**,符合条件;

  2. Filter 处理:去掉/one前缀,请求变成/serviceOne

  3. 路由转发:通过负载均衡找到 service-one 的实例(8001 或 8004),转发请求。

2.3 Gateway 的工作流程:请求怎么走?

结合我们的微服务,Gateway 的完整工作流程我们画成图更清楚:

我们要注意的关键点

  • Filter 分 “pre” 和 “post”:pre 在转发前执行(比如鉴权),post 在响应后执行(比如加日志);

  • 负载均衡是内置的:Gateway 会自动从 Nacos 拿服务实例,和我们之前学的 LoadBalancer 逻辑一样。

3. 实战:我们亲手搭建 Gateway 子项目

        该案例是在我们之前的 “父项目 + ServiceOne/Two/Three/OneCopy” 基础上,新增 Gateway 子项目,让所有请求都通过 Gateway 转发。我们一步步来,重点关注 “依赖配置”“路由规则”“易错点”。

步骤 1:新建 Gateway 子项目(和之前建 ServiceOne 一样)

  1. 在父项目上右键→New→Module→Maven,项目名填 “Gateway”;

  2. 配置 pom.xml(核心是引入 Gateway 和 Nacos 依赖,排除冲突包);

  3. 写 application.yml(配置端口、Nacos 地址、路由规则);

  4. 写主类(加注解开启服务发现)。

步骤 2:配置 pom.xml(重点:排除 MVC 依赖,避免冲突)

        这是最容易踩坑的一步!因为 Gateway 基于 WebFlux(响应式编程),和我们父项目继承的spring-boot-starter-web(MVC)冲突,必须排除。我们的 pom.xml 配置如下:

 <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>com.zh</groupId>  <!-- 我们父项目的GroupId --><artifactId>springcloud-parent</artifactId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion>​<artifactId>Gateway</artifactId>​<dependencies><!-- 1. Nacos服务发现依赖:Gateway要从Nacos获取服务实例 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>​<!-- 2. Gateway核心依赖:提供网关功能 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>​<!-- 3. 排除父项目继承的spring-boot-starter-web(MVC),否则启动报错! --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>*</groupId>  <!-- 排除这个依赖下的所有子依赖 --><artifactId>*</artifactId></exclusion></exclusions></dependency>​<!-- 4. 负载均衡依赖:Gateway默认集成,但保险起见加上,避免负载均衡不生效 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies></project>

我们的易错点提醒

  • 如果忘了排除spring-boot-starter-web,启动 Gateway 会报 “Circular dependency”(循环依赖)错误,因为 WebFlux 和 MVC 不能共存;

  • 不用额外引入 OpenFeign,Gateway 通过服务名直接转发,和 OpenFeign 不冲突。

步骤 3:配置 application.yml(两种路由方式,我们都学)

        Gateway 的路由配置有两种常见方式:动态路由(基于服务名)自定义路由(带过滤器),我们分别学,因为实际项目中都会用到。

方式 1:动态路由(简单,基于服务名转发)

        这种方式不用手动配每个服务的路由,Gateway 会自动从 Nacos 获取服务名,按 “http://网关地址/服务名/接口路径” 转发,适合我们快速测试。

我们的 application.yml 配置:

 server:port: 8088  # 网关的端口,我们选8088(别和其他服务冲突)spring:application:name: service-gateway  # 网关的服务名,注册到Nacos用cloud:nacos:# Nacos服务发现配置:网关要从Nacos拿其他服务的实例discovery:server-addr: 127.0.0.1:8848  # 我们本地的Nacos地址service: ${spring.application.name}gateway:# 核心:开启动态路由(基于服务名转发)discovery:locator:enabled: true  # 开启后,Gateway会自动按“服务名”路由# 可选:lower-case-service-id: true  # 服务名不区分大小写(比如Service-One也能匹配service-one)

我们的调用逻辑

  • 之前直接调用 ServiceOne:http://localhost:8001/serviceOne

  • 现在通过 Gateway 调用:http://localhost:8088/service-one/serviceOne

  • 原理:Gateway 看到service-one,会从 Nacos 找 service-one 的实例(8001/8004),然后转发请求,还会自动负载均衡。

方式 2:自定义路由(灵活,带过滤器,实际项目常用)

        动态路由虽然简单,但路径里带服务名(比如/service-one/)不够友好,我们可以通过自定义路由,把路径改成更简洁的(比如/one/→service-one),还能加过滤器处理路径。

我们修改 application.yml,用routes配置自定义路由:

 server:port: 8088spring:application:name: service-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8848service: ${spring.application.name}gateway:# 关闭动态路由(和自定义路由二选一,避免冲突)# discovery:#   locator:#     enabled: false# 核心:自定义路由规则routes:# 第一条路由:匹配/one/**→service-one- id: route-service-one  # 路由唯一ID(随便起,但不能重复)uri: lb://service-one  # 目标地址:lb=负载均衡,转发到service-onepredicates:  # 匹配条件:请求路径以/one/开头- Path=/one/**filters:  # 过滤器:去掉路径的第一个前缀(/one)- StripPrefix=1# 第二条路由:匹配/two/**→service-two- id: route-service-twouri: lb://service-twopredicates:- Path=/two/**filters:- StripPrefix=1# 第三条路由:匹配/three/**→service-three- id: route-service-threeuri: lb://service-threepredicates:- Path=/three/**filters:- StripPrefix=1

我们重点理解过滤器 StripPrefix=1

  • 客户端请求:http://localhost:8088/one/serviceOne

  • Filter 处理:StripPrefix=1 表示 “去掉路径的第一个/后的部分”,也就是去掉/one,剩下/serviceOne

  • 最终转发:Gateway 把请求转发到 service-one 的/serviceOne接口,和我们之前的调用逻辑一致。

我们的调用对比

微服务动态路由调用地址自定义路由调用地址
ServiceOnehttp://8088/service-one/serviceOnehttp://8088/one/serviceOne
ServiceTwohttp://8088/service-two/serviceTwohttp://8088/two/serviceTwo
ServiceThreehttp://8088/service-three/serviceThree_toOnehttp://8088/three/serviceThree_toOne

步骤 4:写 Gateway 的主类(最简单的主类)

        Gateway 的主类不用加复杂配置,只需要开启服务发现即可,因为路由规则都在 application.yml 里配好了:

package com.zh.gateway;​import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;​@SpringBootApplication@EnableDiscoveryClient  // 开启服务发现:让Gateway能从Nacos获取其他服务的实例public class GatewayApplication {public static void main(String[] args) {// 启动网关,加载application.yml的路由配置SpringApplication.run(GatewayApplication.class, args);}}

我们的注意点

  • 主类不用加@EnableFeignClients,因为 Gateway 是转发请求,不用调用 Feign 接口;

  • 不用配置 RestTemplate,Gateway 有自己的转发机制。

4. 结果验证:我们亲手测试 Gateway 是否生效

        和之前测试 LoadBalancer、OpenFeign 一样,我们按 “启动顺序→Nacos 验证→接口调用” 的步骤来,确保 Gateway 能正常转发和负载均衡。

步骤 1:按顺序启动服务(重要,避免依赖问题)

  1. 先启动 Nacos Server(确保 8848 端口可用);

  2. 再启动服务提供者:ServiceOne(8001)、ServiceOneCopy(8004)、ServiceTwo(8002);

  3. 然后启动 ServiceThree(8003);

  4. 最后启动 Gateway(8088)。

        我们的检查点:启动后看每个服务的控制台,没有报错(尤其是 Gateway,别出现 MVC 冲突错误)。

步骤 2:查看 Nacos 服务列表(确认 Gateway 注册成功)

访问http://127.0.0.1:8848/nacos,在 “服务列表” 里能看到service-gateway(Gateway 的服务名),其他服务也都在:

服务名实例数健康实例数说明
service-gateway11Gateway 实例
service-one22ServiceOne(8001)+OneCopy(8004)
service-two11ServiceTwo(8002)
service-three11ServiceThree(8003)

我们的确认点:所有服务的 “健康实例数” 等于 “实例数”,说明都正常注册到 Nacos 了。

步骤 3:调用接口验证(两种路由方式都测)

我们分别测试 “动态路由” 和 “自定义路由”,还要验证负载均衡是否生效。

测试 1:动态路由(基于服务名)
  • 调用 ServiceOne 的接口:http://localhost:8088/service-one/serviceOne

    • 第一次返回(来自 8001):{"code":0,"message":"Service one method return!"}

    • 第二次返回(来自 8004):{"code":0,"message":"Service one \"COPY\" method return!"}

    • 结论:Gateway 自动负载均衡,和我们之前学的 LoadBalancer 效果一样。

  • 调用 ServiceThree 的接口:http://localhost:8088/service-three/serviceThree_toOne

    • 第一次返回 data 是 ServiceOne(8001)的结果;

    • 第二次返回 data 是 ServiceOneCopy(8004)的结果;

    • 结论:Gateway 转发到 ServiceThree 后,ServiceThree 内部调用 ServiceOne 依然负载均衡,链路完整。

测试 2:自定义路由(带 StripPrefix 过滤器)
  • 调用 ServiceOne 的接口:http://localhost:8088/one/serviceOne

    • 结果和动态路由一样,会轮询 8001 和 8004;

    • 原理:Filter 去掉/one前缀,转发到service-one/serviceOne

  • 调用 ServiceTwo 的接口:http://localhost:8088/two/serviceTwo

    • 返回:{"code":0,"message":"Service two method return!"}

    • 结论:路由匹配成功,转发到 ServiceTwo。

我们的成就感:现在我们只用记 Gateway 的 8088 端口,就能调用所有微服务的接口,前端再也不用记多个地址了!

5. 我们的重点 & 易错点总结(避坑指南)

        Gateway 配置不算复杂,但初学者容易踩 “依赖冲突”“路由不匹配” 的坑,我们整理了最常见的问题,帮我们后续编码少走弯路:

5.1 重点知识(必须记住)

  1. Gateway 的定位:微服务的统一入口,所有客户端请求都走 Gateway,服务内部调用(如 ServiceThree→ServiceOne)可以不走 Gateway;

  2. 路由匹配顺序routes里的路由是 “按顺序匹配” 的,前面的路由匹配成功,就不会走后面的,所以我们要把精确的路由放前面(比如/one/detail/**/one/**前面);

  3. StripPrefix 的作用:去掉路径前缀,比如StripPrefix=2会去掉两个前缀(/one/two/serviceOne/serviceOne),根据我们的路由需求调整;

  4. 负载均衡内置:Gateway 默认集成 LoadBalancer,不用加@LoadBalanced,只要 uri 用lb://服务名,就会自动负载均衡。

5.2 易错点 & 解决方案(我们踩过的坑)

易错点描述我们的解决方案
启动 Gateway 报 “循环依赖” 错误忘了排除spring-boot-starter-web,在 pom.xml 里把这个依赖的子依赖全部排除(参考步骤 2 的 pom 配置)
自定义路由不生效,一直 4041. 检查predicates的 Path 是否带/**(比如/one要改成/one/**);2. 检查 uri 是否是lb://服务名(别写成 http://IP: 端口);3. 检查服务名是否和 Nacos 里的一致(大小写敏感)
StripPrefix 过滤器没生效,路径不对1. 确认filters里写的是StripPrefix=1(别少了 “=1”);2. 检查请求路径是否符合predicates(比如/one/serviceOne才会触发过滤器)
Gateway 能转发,但负载均衡不生效1. 确认引入了spring-cloud-starter-loadbalancer依赖;2. uri 必须用lb://服务名(别写成 http:// 固定 IP);3. 目标服务有多个实例(比如 service-one 要有 8001 和 8004 两个实例)

6. 关联我们之前的知识:完整微服务链路终于通了!

学完 Gateway 后,我们的微服务架构链路就完整了,我们梳理一下整个流程:

  1. 服务注册:ServiceOne、ServiceTwo、ServiceThree、Gateway 启动后,都注册到 Nacos;

  2. 客户端请求:前端发请求http://localhost:8088/one/serviceOne(通过 Gateway);

  3. 网关转发:Gateway 根据路由规则(/one/**→lb://service-one),去掉/one前缀,从 Nacos 找 service-one 的实例(8001/8004);

  4. 负载均衡:Gateway 选一个实例(比如 8001),转发请求到http://127.0.0.1:8001/serviceOne

  5. 服务响应:ServiceOne 返回 JSON 结果,经过 Gateway 的 post 过滤器,返回给前端。

我们的完整链路图

7. 我们的后续学习方向

Gateway 是微服务的 “入口”,后续我们还需要给它加更多 “安全防护” 和 “监控能力”:

  1. 网关鉴权:在 Gateway 里加过滤器,验证客户端的 token(比如 JWT),没登录的请求直接拦截,不用每个服务都写鉴权;

  2. 限流熔断:用 Gateway 的内置限流功能(比如 RedisRateLimiter),限制每秒的请求数,避免服务被冲垮;

  3. 日志监控:在 Gateway 的 post 过滤器里加日志,记录每个请求的响应时间、状态码,方便我们排查问题;

  4. 跨域处理:在 Gateway 里统一配置跨域(比如允许前端的 8080 端口访问),不用每个服务都配@CrossOrigin

总结

        Gateway 对我们的微服务架构来说,就像 “大门” 一样重要 —— 它解决了我们之前 “地址难记、认证分散、跨域麻烦” 的问题,还和我们学的 Nacos、LoadBalancer 无缝集成。现在我们只用记 Gateway 的地址,就能调用所有微服务的接口,后续维护也更方便。

        记住:Gateway 的核心是 “路由 + 过滤器”,我们不用死记配置,而是根据业务需求调整路由规则和过滤器,比如我们想让/api/order/**转发到订单服务,就配置一条对应的 Route,灵活运用即可。

http://www.dtcms.com/a/415297.html

相关文章:

  • 基于 PyTorch 的模型测试与全局平均池化实践
  • 买软件网站建设福田祥菱v1单排
  • 江阴网站设计哪家好百度云用流量做网站
  • C++ 类型推导(第二部分)
  • C 内存布局
  • 编译Duckdb机器学习插件QuackML
  • 帝国cms仿站工具学网站建设 去那里
  • 《R for Data Science (2e)》免费中文翻译 (第9章) --- Layers(1)
  • 网站注册时间查询aspnet网站开发pdf
  • 企业管理说白了是干嘛的seo优化排名教程
  • 医院建设网站网页ui设计尺寸规范
  • 网站模板批量下载推广电话
  • 织梦网站如何做seo我的家乡网页设计模板
  • 平顶山哪里有做网站的公司dede后台网站主页
  • 客户做网站需要提供什么网站建设洽谈
  • Redis实战篇-登录校验
  • PostgreSQL数据类型怎么选才高效不踩坑?
  • 岳阳网站开发建设小程序模板消息推送规则
  • 文本编码--BPE
  • 信息安全仿真环境十一
  • 淡水网站建设跨境电商运营基础知识
  • 山西省建设厅官网站小公司使用的网站开发
  • 红宝书 基础词回忆
  • 【靶场练习】--DVWA第三关CSRF(跨站请求伪造)全难度分析
  • 商城网站建设正规公司光辉网站建设公司
  • Linux读者写者问题与读写锁
  • Kurt-Blender零基础教程:第3章:材质篇——第2节:凹凸感和置换形变;混合材质节点和NodeWrangler的五大用法;简单的UV纹理绘制
  • 潍坊高密网站建设wordpress myisam
  • 南充能够建设网站的公司有网站制作专家
  • @Import 导入bean对象