Spring Cloud Gateway 重写 URL
目录
1、简介
2、Spring Cloud Gateway 快速回顾
3、基于配置的 URL 重写
4、基于 DSL 的 URL 重写
5、测试
6、总结
1、简介
Spring Cloud Gateway 的常见用例是作为一个网关,代理一个或多个服务,从而为客户端提供更简单的消费方式。
本文将带你了解如何在将请求发送到后端之前,通过重写 URL 来自定义暴露的 API 的不同方式。
2、Spring Cloud Gateway 快速回顾
Spring Cloud Gateway 项目是在流行的 Spring Boot 2 和 Project Reactor 的基础上构建的,因此继承了其主要特性:
- 响应式,资源占用低
- 支持 Spring Cloud 生态系统的所有功能(服务发现、配置等)
- 使用标准 Spring 模式轻松扩展和/或定制
这里只列出它的主要概念,更多详细信息请参阅 中文文档:
- Route:路由,在网关中,匹配的传入请求会经历一系列的处理步骤。
- Predicate:针对 ServerWebExchange 进行评估的 Java 8 Predicate。
- Filters:可以检查、更改 ServerWebExchange 的 GatewayFilter 实例。网关支持全局 Filter 和按路由的 Filter。
简而言之,接收请求的处理顺序如下:
- 网关使用与每条路由相关的 Predicate 来查找哪条路由可以处理请求。
- 一旦找到路由,请求(ServerWebExchange 实例)就会通过每个配置的 Filter,直到最终发送到后端。
- 当后端发送回响应或出现错误(例如超时或连接重置)时,Filter 可以再次处理响应,然后再将其发送回客户端。
3、基于配置的 URL 重写
回到本文的主题,让我们看看如何定义一个路由,在将请求发送到后端之前重写传入的 URL。例如,假设输入的请求格式为 /api/v1/customer/*,后端 URL 应为 http://v1.customers/api/*。这里,使用 “*” 来表示 “在此之后的任何内容”。
只需在应用的配置中添加几个属性,就可以创建基于配置的重写。为了更好的可读性,使用基于 YAML 的配置,这些信息可以来自任何受支持的 PropertySource:
spring:cloud:gateway:routes:- id: rewrite_v1uri: ${rewrite.backend.uri:http://example.com}predicates:- Path=/v1/customer/**filters:- RewritePath=/v1/customer/(?<segment>.*),/api/$\{segment}
分析一下这个配置。首先,路由有一个 id,这只是它的标识符。其次,uri 属性给出了后端 URI。注意,这里只考虑了主机名/端口,因为最终路径来自重写逻辑。
predicates 属性定义了激活此路由必须满足的条件。在本例中,我们使用了 Path predicate,它使用类似于 Ant 的路径表达式来匹配传入请求的路径。
最后,filters 属性具有实际的重写逻辑。RewritePath Filter 需要两个参数:正则表达式和替换字符串。Filter 的实现方式是,使用提供的参数作为参数,在请求的 URI 上执行 replaceAll() 方法。
Spring 处理配置文件的方式有一个注意事项,那就是不能使用标准的 ${group} 替换表达式,因为 Spring 会认为这是一个属性引用,并尝试替换其值。为了避免这种情况,需要在 $ 和 { 字符之间添加反斜杠,Filter 会在使用它作为实际替换表达式之前移除反斜杠。
4、基于 DSL 的 URL 重写
虽然 RewritePath 非常强大且易于使用,但在重写规则具有某些动态特性的情况下,它就显得力不从心了。根据情况,可以使用基于 DSL 的方法创建路由。我们需要做的就是创建一个 RouteLocator Bean 来实现路由的逻辑。
举个例子,创建一个简单的路由,和上面一样,使用正则表达式重写传入的 URI。但这次,替换字符串将在每次请求时动态生成:
@Configuration
public class DynamicRewriteRoute {@Value("${rewrite.backend.uri}")private String backendUri;private static Random rnd = new Random();@Beanpublic RouteLocator dynamicZipCodeRoute(RouteLocatorBuilder builder) {return builder.routes().route("dynamicRewrite", r ->r.path("/v2/zip/**").filters(f -> f.filter((exchange, chain) -> {ServerHttpRequest req = exchange.getRequest();addOriginalRequestUrl(exchange, req.getURI());String path = req.getURI().getRawPath();String newPath = path.replaceAll("/v2/zip/(?<zipcode>.*)", "/api/zip/${zipcode}-" + String.format("%03d", rnd.nextInt(1000)));ServerHttpRequest request = req.mutate().path(newPath).build();exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());return chain.filter(exchange.mutate().request(request).build());})).uri(backendUri)).build();}
}
在这里,动态部分只是将一个随机数添加到替换字符串中。在实际应用中可能会有更复杂的逻辑,但基本机制如下所示。
首先,它调用了 addOriginalRequestUrl() 方法,该方法来自 ServerWebExchangeUtils 类,用于将原始 URL 存储在 exchange attribute GATEWAY_ORIGINAL_REQUEST_URL_ATTR 下。该属性的值是一个 List,我们将在进行任何修改之前将接收到的 URL 追加到该 List 中,并且网关在处理 X-Forwarded-For Header 时会内部使用该 List。
其次,应用重写逻辑后,必须将修改后的 URL 保存在 GATEWAY_REQUEST_URL_ATTR exchange attribute 中。这一步在文档中没有直接提及,但可以确保我们的自定义 Filter 与其他可用 Filter 良好地协同工作。
5、测试
使用标准的 JUnit 5 来测试我们的重写规则。
稍加改动:使用基于 Java SDK 的 com.sun.net.httpserver.HttpServer 类启动一个简单的服务器。使用随机端口,从而避免端口冲突。
不过,这种方法的缺点是,必须找出实际分配给服务器的端口,并将其传递给 Spring,以便使用它来设置路由的 uri 属性。幸运的是,Spring 为我们提供了一个优雅的解决方案: @DynamicPropertySource,在此,使用它启动服务器,并使用绑定端口的值注册一个属性:
@DynamicPropertySource
static void registerBackendServer(DynamicPropertyRegistry registry) {registry.add("rewrite.backend.uri", () -> {HttpServer s = startTestServer();return "http://localhost:" + s.getAddress().getPort();});
}
测试 Handler 只需在响应体中回传接收到的 URI 即可。这样就能验证重写规则是否按预期运行。
@Test
void testWhenApiCall_thenRewriteSuccess(@Autowired WebTestClient webClient) {webClient.get().uri("http://localhost:" + localPort + "/v1/customer/customer1").exchange().expectBody().consumeWith((result) -> {String body = new String(result.getResponseBody());assertEquals("/api/customer1", body);});
}
6、总结
本文介绍了在 Spring Cloud Gateway 中如何通过配置文件和 DSL 来重写路由 URL。
相关文章:
Spring Cloud Gateway 重写 URL
目录 1、简介 2、Spring Cloud Gateway 快速回顾 3、基于配置的 URL 重写 4、基于 DSL 的 URL 重写 5、测试 6、总结 1、简介 Spring Cloud Gateway 的常见用例是作为一个网关,代理一个或多个服务,从而为客户端提供更简单的消费方式。 本文将带你…...
【C语法学习】10 - scanf()函数
文章目录 0 前言1 函数原型2 参数2.1 格式字符串2.1.1 转换说明 2.2 参数列表 3 返回值4 读取机制4.1 基本概念4.2 转换说明4.3 读取过程4.4 读取示例4.5 多参数 6 示例6.1 示例16.2 示例26.3 示例36.4 示例4 0 前言 scanf()函数虽然使用起来较为灵活,但是其读取机…...
ffmpeg mp3截取命令,视频与mp3合成带音频视频命令
从00:00:03.500开始截取往后长度到结尾的mp3音频(这个更有用,测试好用) ffmpeg -i d:/c.mp3 -ss 00:00:03.500 d:/output.mp3 将两个音频合并成一个音频(测试好用) ffmpeg -i "concat:d:/c.mp3|d:/output.mp3&…...
文件夹还在,里面文件没了?问题这样解决
文件夹还在但文件无故消失怎么办?文件的消失对于我们来说可能是个令人沮丧且困惑的问题。有时候,我们可能会发现文件夹依然存在,但其中的文件却消失了。在这篇文章中,我们将探讨为什么电脑文件会无故消失的原因,并提供…...
使用 OpenCV 和 Tesseract OCR 进行车牌识别
您将了解自动车牌识别。我们将使用 Tesseract OCR 光学字符识别引擎(OCR 引擎)来自动识别车辆牌照中的文本。 Python-tesseract: Py-tesseract 是 Python 的光学字符识别 (OCR) 工具。也就是说,它将识别并“读取”图像中嵌入的文本。Python-tesseract 是 Google 的 Tessera…...
What exactly are the practices involved in DevOps?
目录 1. Continuous Integration (CI) 2. Continuous Deployment (CD) 3. Infrastructure as Code (IAC) 4. Configuration Management 5. Monitoring and Logging 6. Automated Testing 7. Collaboration and Communication 8. Microservices Architecture 9. Conta…...
Spring底层原理(五)
Spring底层原理(五) 本章内容 介绍Aware接口与InitializingBean接口、Bean的初始化与销毁、Scope Aware接口 作用:用于注入一些与容器相关的信息 类名作用BeanNameAware注入Bean的名称BeanFactoryAware注入BeanFactory容器ApplicationContextAware注入ApplicationContext容…...
算法的基本概念(数据结构与算法)
数据结构是指数据元素之间的关系和组织方式,在计算机科学中被广泛应用于存储和操作数据的方法和技术。 数据元素: 数据元素是构成数据的基本单位,可以是数字、字符、记录等。 数据项: 数据元素中的一个部分,表示一个属…...
高阶数据结构学习——LRU Cache
文章目录 1、了解LRU Cache(Least Recently Used缩写)2、代码实现 1、了解LRU Cache(Least Recently Used缩写) Cache是缓存,在磁盘和内存之间,内存和寄存器之间都存在,CPU和内存之间存在三级缓…...
代码冲突解决
远程仓库修改 本地代码修改 接下来我们push一下 如果使用IDE 冲突内容如下: 我们可以使用自带的工具进行修改 我们选择接受自己改动的即可 如果使用git工具怎么去处理呢 远程分支是这样 本地是这样的 add和commit之后,再pull,最后pus…...
c/c++程序的内存开辟时 的内存情况
我们写的代码都是要存放在内存空间中的,我们经常说堆区,静态区,还有栈区,相信很多人不是很明白,在今天这篇博客中让大家对它们有一个粗略的认识 1.栈区(static) 在执行函数时,函数内…...
【linux常用命令+vi编辑器_2023.11.3】
芯片开发 Linux/Unix(环境) EDA工具TCL(波形) SVN/GIT(版本控制) Makefile(脚本语言) Perl/Python(脚本语言) Vim/Gvim(编辑器) 命令…...
okhttp post请求 header post参数加密遇到的两个问题
如果你对于网络请求用了https后是否还有必要对参数加密有疑问可以看我上篇的文章:网络安全https 记得耐心看完,下面说问题: Caused by: java.lang.IllegalArgumentException: Unexpected char 0x0a 一开始以为是okhttp框架对特殊字符做了现在…...
什么是Webpack的loader和plugin?它们的作用是什么?
聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...
ESXi for ARM 最新下载地址
由于VMware决定关闭 flings.vmware.com 网站,内容被迁移到不同的地方,网站跳转到 Code Samples and PowerCLI Example Scripts | VMware - VMware {code} ESXi for ARM的下载地址迁移到了 https://customerconnect.vmware.com/downloads/get-download?…...
2. 网络之网络编程
网络编程 文章目录 网络编程1. UDP1.1 DatagramSocket1.1.1 DatagramSocket 构造方法1.1.2 DatagramSocket 方法: 1.2 DatagramPacket1.2.1 DatagramPacket构造方法1.2.2 DaragramPacket方法1.2.3InetSocketAddress API 1.3 UDP回显服务器1.3.1 框架结构1.3.2 读取请…...
工作数字化的中国历程 | 从 OA 到 BPM 到数字流程自动化
业务流程是由“活动”(或称“工作任务”)构成的,在企业里的所有工作是不是都叫流程,或者属于流程的一部分,这个概念很绕,我觉得没有必要去做学究气的辨析。我曾经提出过一个从工作的两个特性(产…...
6-1 二叉排序树查找操作
description 本题要求实现二叉排序树的查找操作。 函数接口定义: BSTree SearchBST(BSTree T,ElemType e); 其中BSTree结构定义如下: typedef int ElemType; typedef struct BSTNode { ElemType data; struct BSTNode *lchild,*rchild; }BSTNode,*BS…...
服务上千家企业,矩阵通2.0重磅上线,全链路管理新媒体矩阵
自上线以来 矩阵通已服务了上千家企业级客户 覆盖汽车、家居、媒体、金融、教育等多个行业 矩阵通1.0时代 我们以“数据”为基座打造出10功能 帮助企业轻松管理新媒体矩阵 实现账号管理、数据分析、竞对监测、 人员考核、风险监管等需求 而现在 矩阵通2.0重磅上线 新增…...
【代码随想录】算法训练计划11
1、20. 有效的括号 题目: 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
