6000 字 | 16 图,吃透 Spring Cloud Gateway 原理
本篇给大家带来的是微服务框架中非常重要的一个组件API 网关。前言在 PassJava 项目中我用到了 Spring Cloud Gateway 作为 API 网关客户端的所有的请求都是先经过网关然后再转发到会员微服务、题目微服务等。比如 API 网关和会员微服务对应的访问地址如下API 网关地址http://localhost:8060会员微服务地址http://localhost:14000客户端请求都是访问的 API 网关然后网关转发到会员微服务客户端无需知道会员微服务的地址。本篇将会以 PassJava 作为案例进行讲解。PassJava 开源地址https://github.com/Jackson0714/PassJava-Platform为什么需要 API 网关在 SpringBoot 单体架构中一般只有一个后端服务如下图所示单体架构访问示例图但是在 SpringCloud 微服务架构中往往有多个微服务这些微服务可能部署在不同的机器上而且一个微服务可能会扩容成多个相同的微服务组成微服务集群。微服务架构访问示例图这种情况下会存在如下问题如果需要添加鉴权功能则需要对每个微服务进行改造。如果需要对流量进行控制则需要对每个微服务进行改造。跨域问题需要对每个微服务进行改造。存在安全问题每个微服务需要暴露自己的 Endpoint 给客户端。Endpoint 就是服务的访问地址 端口。比如下面的地址http://order.passjava.cn:8000灰度发布、动态路由需要对每个微服务进行改造。这个问题的痛点是各个微服务都是一个入口有没有办法统一入口呢解决这个问题的方式就是在客户端和服务器之间加个中间商就好了呀只有中间商一个入口这个中间商就是网关。还有一个细节问题多个微服务之间是如何通信的这就要用到远程调用组件了比如 OpenFeign。但是服务之间的调用是需要知道对方的 Endpoint 的如果一个服务有多个微服务就需要通过负载均衡组件进行流量分发。那微服务之间不就暴露 Endpoint 了吗这个没有问题毕竟只是后端服务知道外界是不知道的。为了帮助大家更容易理解网关的作用这里有个网关、客户端、微服务的三方通话。网关对话网关客户端你好你现在可以只跟我通信了我可以将你本来想发给微服务的流量进行转发微服务处理完之后将结果返回给我我再给你。客户端你没有赚差价吧API 网关我可能会加些请求头、做下认证、鉴权、限流等。客户端微服务不是自己可以做吗API 网关但是每个微服务都得自己加这就很麻烦了都交给我就好了。微服务网关你好你会为我保密我的地址对吗API 网关当然我给客户端看的是我自己的地址客户端不需要知道你的地址只需要知道你的 API 是哪个就行剩下的交给我来转发给你。API 网关选型对比业界比较出名的网关Spring Cloud Gateway、Netflix Zuul、Nginx、Kong、Alibaba Tengine。作为 Spring Cloud 全家桶中的一款组件当然选择 Spring Cloud Gateway 了。最开始 Spring Cloud 推荐的网关是 Netflix Zuul 1.x但是停止维护了后来又有 Zuul 2.0但是因为开发延期比较严重Spring Cloud 官方自己开发了 Spring Cloud Gateway 网关组件用于代替 Zuul 网关。所以本篇我们只会讲解 Spring Cloud Gateway 网关组件。Spring Cloud Gateway 的工作流程Gateway 的工作流程如下图所示①路由判断客户端的请求到达网关后先经过 Gateway Handler Mapping 处理这里面会做断言Predicate判断看下符合哪个路由规则这个路由映射后端的某个服务。②请求过滤然后请求到达 Gateway Web Handler这里面有很多过滤器组成过滤器链Filter Chain这些过滤器可以对请求进行拦截和修改比如添加请求头、参数校验等等有点像净化污水。然后将请求转发到实际的后端服务。这些过滤器逻辑上可以称作 Pre-FiltersPre 可以理解为“在...之前”。③服务处理后端服务会对请求进行处理。④响应过滤后端处理完结果后返回给 Gateway 的过滤器再次做处理逻辑上可以称作 Post-FiltersPost 可以理解为“在...之后”。⑤响应返回响应经过过滤处理后返回给客户端。小结客户端的请求先通过匹配规则找到合适的路由就能映射到具体的服务。然后请求经过过滤器处理后转发给具体的服务服务处理后再次经过过滤器处理最后返回给客户端。Spring Cloud Gateway 的断言断言Predicate这个词听起来极其深奥它是一种编程术语我们生活中根本就不会用它。说白了它就是对一个表达式进行 if 判断结果为真或假如果为真则做这件事否则做那件事。在 Gateway 中如果客户端发送的请求满足了断言的条件则映射到指定的路由器就能转发到指定的服务上进行处理。断言配置的示例如下配置了两个路由规则有一个 predicates 断言配置当请求 url 中包含 api/thirdparty就匹配到了第一个路由 route_thirdparty。代码示例来自我的开源项目 PassJava断言配置接下来我们看下 Route 路由和 Predicate 断言的对应关系断言和路由的对应关系原理图一对多一个路由规则可以包含多个断言。如上图中路由 Route1 配置了三个断言 Predicate。同时满足如果一个路由规则中有多个断言则需要同时满足才能匹配。如上图中路由 Route2 配置了两个断言客户端发送的请求必须同时满足这两个断言才能匹配路由 Route2。第一个匹配成功如果一个请求可以匹配多个路由则映射第一个匹配成功的路由。如上图所示客户端发送的请求满足 Route3 和 Route4 的断言但是 Route3 的配置在配置文件中靠前所以只会匹配 Route3。常见的 Predicate 断言配置如下所示假设匹配路由成功后转发到 http://localhost:9001常见的 Predicate 断言配置代码演示下面演示 Gateway 中通过断言来匹配路由的例子。新建一个 Maven 工程引入 Gateway 依赖。dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency新建 application.yml 文件添加 Gateway 的路由规则。spring: cloud: gateway: routes: - id: route_qq uri: http://www.qq.com predicates: - Queryurl,qq - id: route_baidu uri: http://www.baidu.com predicates: - Queryurl,baidu server: port: 8060第一条路由规则断言为 Queryurl,qq表示当请求路径中包含 urlqq则跳转到http://www.qq.com第二条路由规则当请求路径中包含 urlbaidu则跳转到http://www.baidu.comSpring Cloud Gateway 动态路由在微服务架构中我们不会直接通过 IP 端口的方式访问微服务而是通过服务名的方式来访问。如下图所示微服务中加入了注册中心多个微服务将自己注册到了注册中心这样注册中心就保存了服务名和 IP端口的映射关系。微服务注册到注册中心接下来我们来看下加入 Gateway 后请求是如何进行转发的。客户端先将请求发送给 Nginx然后转发到网关网关经过断言匹配到一个路由后将请求转发给指定 uri这个 uri 可以配置成 微服务的名字比如 passjava-member。那么这个服务名具体要转发到哪个 IP 地址和端口上呢这个就依赖注册中心的注册表了Gateway 从注册中心拉取注册表就能知道服务名对应具体的 IP 端口如果一个服务部署了多台机器则还可以通过负载均衡进行请求的转发。原理如下图所示网关注册中心对应的配置为 uri 字段如下所示uri: lb://passjava-question表示将请求转发给 passjava-question 微服务且支持负载均衡。lb 是 loadbalance负载均衡) 单词的缩写。那什么叫动态路由呢当 passjava-question 服务添加一个微服务或者 IP 地址更换了Gateway 都是可以感知到的但是配置是不需要更新的。这里的动态指的是微服务的集群个数、IP 和端口是动态可变的。代码示例案例调用 OSS 第三方服务上传文件到 OSS。基于 PassJava 项目前提前端页面配置的统一访问路径是网关的地址http://localhost:8060/api/OSS 服务对应的地址是http://localhost:14000。期望结果将前端请求http://localhost:8060/api/thirdparty/v1/admin/oss/getPolicy转发到 OSS 服务。http://localhost:14000/thirdparty/v1/admin/oss/getPolicy配置网关spring: cloud: gateway: routes: - id: route_thirdparty # 第三方微服务路由规则 uri: lb://passjava-thirdparty # 负载均衡将请求转发到注册中心注册的 passjava-thirdparty 服务 predicates: # 断言 - Path/api/thirdparty/** # 如果前端请求路径包含 api/thirdparty则应用这条路由规则 filters: #过滤器 - RewritePath/api/(?segment.*),/$\{segment} # 将跳转路径中包含的api替换成空测试上传文件成功。接下来我们看下 Gateway 非常重要且核心的功能过滤器。Spring Cloud Gateway 的过滤器网关顾名思义就是网络中的一道关卡可以统一对请求和响应进行一些操作。过滤器 Filter 的分类过滤器 Filter 按照请求和响应可以分为两种Pre类型和Post类型。Pre 类型在请求被转发到微服务之前对请求进行拦截和修改例如参数校验、权限校验、流量监控、日志输出以及协议转换等操作。Post 类型微服务处理完请求后返回响应给网关网关可以再次进行处理例如修改响应内容或响应头、日志输出、流量监控等。另外一种分类是按照过滤器 Filter 作用的范围进行划分GlobalFilter全局过滤器应用在所有路由上的过滤器。局部过滤器GatewayFilter局部过滤器应用在单个路由或一组路由上的过滤器。标红色表示比较常用的过滤器。整理了一份 27 种自带的 GatwayFilter 过滤器。具体怎么用呢这里有个示例如果 URL 匹配成功则去掉 URL 中的 “api”。filters: #过滤器 - RewritePath/api/(?segment.*),/$\{segment} # 将跳转路径中包含的 “api” 替换成空当然我们也可以自定义过滤器本篇不做展开。全局过滤器整理了一份全局过滤器的表格具体用法可以参照官方文档。官方文档https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_global_filters全局过滤器最常见的用法是进行负载均衡。配置如下所示spring: cloud: gateway: routes: - id: route_member # 第三方微服务路由规则 uri: lb://passjava-member # 负载均衡将请求转发到注册中心注册的 passjava-member 服务 predicates: # 断言 - Path/api/member/** # 如果前端请求路径包含 api/member则应用这条路由规则 filters: #过滤器 - RewritePath/api/(?segment.*),/$\{segment} # 将跳转路径中包含的api替换成空这里有个关键字lb用到了全局过滤器LoadBalancerClientFilter当匹配到这个路由后会将请求转发到 passjava-member 服务且支持负载均衡转发也就是先将 passjava-member 解析成实际的微服务的 host 和 port然后再转发给实际的微服务。实现简单的 token 认证在用 Gateway 做登录认证的时候通常需要我们自定义一个过滤器做登录认证。比如客户端登录时将用户名和密码发送给网关网关转发给认证服务器后如果账号密码正确则拿到一个 JWT token然后客户端再访问应用服务时先将请求发送给网关网关统一做 JWT 认证如果 JWT 符合条件再将请求转发给应用服务。原理如下图所示红色框框的部分就是待会我要演示的部分。案例演示下面做一个简单的认证实例。客户端携带 token 访问 member 服务网关会先校验 token 的合法性验证规则如下当请求的 header 中包含 token且 token admin则认证通过。当验证通过后就会将请求转发给 member 服务。代码示例先定义一个全局过滤器验证 token 的合法性。Component public class GlobalLoginFilter implements GlobalFilter, Ordered { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request exchange.getRequest(); String token request.getHeaders().getFirst(token); if(!StringUtils.isEmpty(token)){ if(admin.equals(token)){ return chain.filter(exchange); } } exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } Override public int getOrder() { return 0; } }测试 token 不正确的场景。先测试在 header 中添加 token123响应结果为 401 Unauthorized没有权限。测试 token 正确的场景。然后测试在 header 中添加 tokenadmin正常返回响应数据。

相关新闻

OpenClaw火爆出圈!246K星!硬核拆解本地化AI助理架构,企业级Agent架构演进至17层!

OpenClaw火爆出圈!246K星!硬核拆解本地化AI助理架构,企业级Agent架构演进至17层!

最近的 AI 开发者圈子里,有一个项目以惊人的速度火爆出圈,它的 GitHub Star 数在短短一个月内飙升到了夸张的 246K,作为对比,沉淀了三年的头部低代码 AI 平台 Dify 目前是 130K 左右。 它就是经历了从 Clawdbot 到 Moltbot &#…

2026/5/17 8:33:03 阅读更多 →
JDK源码之Object

JDK源码之Object

仁从冀匆?? 学习目标 了解什么是变量,并学会定义和更新变量 掌握如何为变量选择合适的数据类型 学会在代码中添加注释,提升可读性 什么是变量 在编程中,变量就像一个带标签的盒子,用来存放某个数据值。 标签(变量名&…

2026/7/5 22:51:20 阅读更多 →
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析

new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析

凑段耘辛1. 基础 1.1 图片加载优化 对于非文章类的大图片先进行一遍压缩,使用各种压缩网站就可以 然后对于各种图片最好都转换为为webp格式,相对于传统格式能降低大小大概四成左右 1.2 gzip压缩 gzip是针对文本类型进行压缩的,例如html、js、…

2026/7/4 20:37:33 阅读更多 →

最新新闻

FinalBurn Neo:打造完美复古街机游戏体验的终极指南

FinalBurn Neo:打造完美复古街机游戏体验的终极指南

FinalBurn Neo:打造完美复古街机游戏体验的终极指南 【免费下载链接】FBNeo FinalBurn Neo - We are Team FBNeo. 项目地址: https://gitcode.com/gh_mirrors/fb/FBNeo FinalBurn Neo(简称FBNeo)是一款开源的街机游戏模拟器&#xff0…

2026/7/6 4:44:23 阅读更多 →
3个关键问题:如何通过WSC API安全管理Windows Defender?

3个关键问题:如何通过WSC API安全管理Windows Defender?

3个关键问题:如何通过WSC API安全管理Windows Defender? 【免费下载链接】no-defender A slightly more fun way to disable windows defender firewall. (through the WSC api) 项目地址: https://gitcode.com/GitHub_Trending/no/no-defender …

2026/7/6 4:44:23 阅读更多 →
珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访

珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访

珀斯与袋鼠岛之旅:波浪岩与野生海鲜市场探访从西澳大利亚州的首府珀斯出发,向东驱车约340公里,可抵达海登附近的波浪岩。这块巨大的花岗岩体高约15米,长度约110米,其岩石表面因长期的风化与水蚀作用,形成了…

2026/7/6 4:42:23 阅读更多 →
叶兴阳双语音标,英语发音工具断层级天花板

叶兴阳双语音标,英语发音工具断层级天花板

功能向实测评价:叶兴阳双语音标,英语发音工具断层级天花板 深耕英语学习多年,试过市面各类音标教辅、发音软件、双语读物,唯有叶兴阳双语音标在功能性上做到全方位无短板,每一项核心功能都精准戳中自学、教学、精读全场…

2026/7/6 4:38:22 阅读更多 →
Python+OpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案对比评测

Python+OpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案对比评测

PythonOpenCV 4.8 与 Tesseract OCR 5.3 车牌识别方案深度评测车牌识别技术作为计算机视觉领域的重要应用,在智能交通、停车场管理等领域发挥着关键作用。本文将深入对比两种主流车牌识别方案:基于OpenCV 4.8的传统图像处理方案和基于Tesseract OCR 5.3的…

2026/7/6 4:38:22 阅读更多 →
3分钟掌握免费Android投屏神器:scrcpy终极使用指南

3分钟掌握免费Android投屏神器:scrcpy终极使用指南

3分钟掌握免费Android投屏神器:scrcpy终极使用指南 【免费下载链接】scrcpy Display and control your Android device 项目地址: https://gitcode.com/GitHub_Trending/sc/scrcpy 还在为手机屏幕太小而烦恼?想要在电脑大屏幕上操作手机应用&…

2026/7/6 4:36:22 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/5 0:03:34 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/5 0:03:34 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/5 0:07:38 阅读更多 →

月新闻