监听 RabbitMQ 延时交换机的消息数、OpenFeign 路径参数传入斜杠无法正确转义
背景
【MQ】一套为海量消息和高并发热点消息,提供高可用精准延时服务的解决方案
我现在有一个需求,就是监听 RabbitMQ 一个延时交换机的消息数,而 RabbitTemplate 是不存在对应的方法来获取的。
而我们在 RabbitMQ 的控制台却可以发现延时交换机的消息数,所以其开放的 http-api 里存在我们需要的数据,通过抓包可得:

而我们查看这个包,构造请求(抓包+分析的技巧这里不做介绍)
当然你完全可以去看 RabbitMQ 的 http-api 开放文档,但是我觉得有点多,还不如直接抓包
URL:
http://rabbithost:15672/api/exchanges/{virtualHost}/{exchange}?msg_rates_age=60&msg_rates_incr=5
Method:
GET
Header:
- Authorization:
"Basic " + EncryptUtil.encodeBase64(String.format("%s:%s", rabbitMQConfig.getUsername(), rabbitMQConfig.getPassword()));
很快我们就能写一个 OpenFeign 客户端:
@FeignClient(name = "rabbitmq-service", url = "${okr.mq.http-api}")
public interface RabbitMQHttpFeignClient {@GetMapping("/exchanges/{virtualHost}/{exchange}?msg_rates_age=60&msg_rates_incr=5")DelayExchangeVO getMessagesDelayed(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization,@PathVariable("virtualHost") String virtualHost,@PathVariable("exchange") String exchange);}
但是你会发现,virtualHost 是带 / 的,但是最终的 url 并没有转义,导致路由出错报了 404
- 400 是参数未通过验证、401 未通过身份认证、403 无权限
先说结论!!!
配置一个 Contract (协议,约定),并设置 decodeSlash 为 false !
@Component
public class OpenFeignConfig {@Beanpublic Contract notdecodeSlashContract(){// 无自定义处理器、默认的 ConversionService、取消 %2F -> / 的解码return new SpringMvcContract(Collections.emptyList(), new DefaultConversionService(), Boolean.FALSE);}}
decodeSlash,直译就是“斜杠解码”
encode: / → %2F
decode: %2F → /
而我们就是阻止 %2F → / ,那我们为什么要阻止呢?
问题分析
首先我们可能会想,它是如何转义的,是传入的时候转义,还是最终一起转义:
如果是最终一起转义,那 / 必然不能被转义,否则那些路由都会失效,所以如果是最终转义,无法满足我们的需求:
这里写了个简单的方法,方便理解
public static <P> String buildUrl(String baseUrl, Map<String, List<String>> queryParams, Map<String, P> pathParams) {queryParams = Optional.ofNullable(queryParams).orElseGet(Map::of);pathParams = Optional.ofNullable(pathParams).orElseGet(Map::of);return UriComponentsBuilder.fromHttpUrl(baseUrl).queryParams(new LinkedMultiValueMap<>(queryParams)).buildAndExpand(pathParams).encode() // 开启译码模式.toUriString();
}
如果在传入的时候转义,才能实现我们的效果:
public static <P> String buildUrl(String baseUrl, Map<String, List<String>> queryParams, Map<String, P> pathParams) {queryParams = Optional.ofNullable(queryParams).orElseGet(Map::of);pathParams = Optional.ofNullable(pathParams).orElseGet(Map::of);return UriComponentsBuilder.fromHttpUrl(baseUrl).encode() // 开启译码模式,这里之后路径参数,/ 也会被转义为 %2F!.queryParams(new LinkedMultiValueMap<>(queryParams)).buildAndExpand(pathParams).toUriString();
}
那 OpenFeign 是哪种呢?如果我们没看源码,我们可能没法判断,但我们可以知道,OpenFeign 在解析路径参数的时候,用的是 PathVariableParameterProcessor
参考文章:文章
通过自定义注解 + 自定义处理器的方式,处理请求,我们通过:
data.indexToExpander().put(context.getParameterIndex(), o -> URLEncoder.encode(String.valueOf(o), Charset.defaultCharset());
我们给 {name} 对应的 index 提供了一个解析器,但是貌似没啥用,如果进行双重编码,导致 % 也也被转义了,但如果只是一重编码,最终 / 还是以 / 的形式出现
这一度让我觉得是玄学!
但我对比了 PathVariableParameterProcessor 类的实现,发现其并没有专门对字符串进行编码,所以我猜测底层是定然编码了的,所以我进行了调试,一步步找到了关键代码:

你会发现,如果传入 / 会被转义成 %2F 也就是说,传入时确实已经编码了,你甚至可以实现传入 %2F 但并设置其已编码,所以不会再次编码,等等无论如何各种方式让字符串为 %2F
但是这里有一个属性 encodeSlash,如果为 false,则将最终结果的 %2F 给重新解码成 /
- 说实话我完全不知道为啥要这样,太放剑了🤣
- 如果是路径参数也是个 uri,也有这样的编程方式,但是我觉得很不规范
这也是我不熟悉 SpringMvcContract 导致的啦,不知道还有这么一个参数 decodeSlash
new SpringMvcContract(Collections.emptyList(), new DefaultConversionService(), false)
decodeSlash 设置为 false 后,encodeSlash 就为 true,%2F 就不会重新解码成 / 了,最终也就能达到我们的预期的效果了
相关文章:
监听 RabbitMQ 延时交换机的消息数、OpenFeign 路径参数传入斜杠无法正确转义
背景 【MQ】一套为海量消息和高并发热点消息,提供高可用精准延时服务的解决方案 我现在有一个需求,就是监听 RabbitMQ 一个延时交换机的消息数,而 RabbitTemplate 是不存在对应的方法来获取的。 而我们在 RabbitMQ 的控制台却可以发现延时交…...
希音(Shein)前端开发面试题集锦和参考答案
用 Node 写过什么工具或 npm 包 在实际开发中,使用 Node 编写过多种实用工具和 npm 包。 自动化构建工具 开发了一个简单的自动化构建工具,用于处理前端项目的资源压缩和合并。在前端项目中,为了优化性能,需要对 CSS 和 JavaScript 文件进行压缩,减少文件体积,同时将多个…...
python全栈-Linux基础
python全栈-Linux基础 文章目录 Linux安装/配置网络配置配置Linux远程登录配置虚拟机内部ip配置真机的ip安装XShell和Xftp目录结构用户和用户组用户管理添加用户useradd查看用户id修改用户usermod (选项)(参数)用户密码设置passed (选项)(参数)删除用户userdel [选项] 用户名 用…...
DeepSeek R1助力,腾讯AI代码助手解锁音乐创作新
目录 1. DeepSeekR1模型简介2. 歌词创作流程2.1 准备工作2.2 歌词生成技巧 3. 音乐制作环节3.1 主流AI音乐生成平台 4. 歌曲欣赏5. 总结展望 1. DeepSeekR1模型简介 腾讯AI代码助手最新推出的DeepSeekR1模型不仅在代码生成方面表现出色,其强大的自然语言处理能力也…...
Git安装与配置
安装部分: Windows:下载官网安装包,双击安装,路径选择(注意是否修改),安装选项(是否勾选某些选项,如提到安装时更换编辑器为Nano)。Linux:通过包管…...
【Linux】自定协议和序列化与反序列化
目录 一、序列化与反序列化概念 二、自定协议实现一个加法网络计算器 (一)TCP如何保证接收方的接收到数据是完整性呢? (二)自定义协议 (三)自定义协议的实现 1、基础类 2、序列化与反序列…...
C++基础系列【19】运算符重载
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
Python-04BeautifulSoup网络爬虫
2025-03-04-BeautifulSoup网络爬虫 记录BeautifulSoup网络爬虫的核心知识点 文章目录 2025-03-04-BeautifulSoup网络爬虫 [toc]1-参考网址2-学习要点3-核心知识点1. 安装2. 导入必要的库3. 发送 HTTP 请求4. 创建 BeautifulSoup 对象5. 解析 HTML 内容5.1 查找标签5.2 根据属性…...
芯科科技通过全新并发多协议SoC重新定义智能家居连接
MG26系列SoC现已全面供货,为开发人员提供最高性能和人工智能/机器学习功能 致力于以安全、智能无线连接技术,建立更互联世界的全球领导厂商Silicon Labs(亦称“芯科科技”,NASDAQ:SLAB),日前宣…...
python-leetcode-零钱兑换 II
518. 零钱兑换 II - 力扣(LeetCode) 这个问题是 完全背包问题 的一个变体,可以使用 动态规划 来解决。我们定义 dp[i] 为凑成金额 i 的硬币组合数。 思路: 定义 DP 数组 设 dp[i] 表示凑成金额 i 的组合数,初始化 dp[…...
【RabbitMQ】Producer之TTL过期时间 - 基于AMQP 0-9-1
这篇文章和大家分享Producer发布消息时如何设置消息过期时间,包括队列级别和消息级别,还有如何设置队列的过期时间。 消息过期时间 给消息设置TTL,在超过TTL值后,消息就会变成dead message(死信)…...
演示汉字笔顺的工具
视频需要审核,还是gif比较方便,本来就不长。 给小学生辅导汉字笔顺的时候,先是发现“百度汉语”里面有很多类似的笔顺的动画,非常方便。但总是需要上网,而且百度上并不提供针对特定汉字的方便的检索途径,加…...
JVM简单了解
一、JVM概述 目录 一、JVM概述 1.jvm的作用 2.jvm的组成 2.1类加载 2.1.1加载 2.1.2链接 2.1.3初始化 2.1.4类加载器分类 2.1.5双亲委派机制 2.2运行时数据区 2.2.1程序计数器 2.2.2虚拟机栈 2.2.3本地方法栈 2.2.4java堆内存 2.2.5方法区 2.3本地方法库接口 …...
【CSS—前端快速入门】CSS 选择器
CSS 1. CSS介绍 1.1 什么是CSS? CSS(Cascading Style Sheet),层叠样式表,用于控制页面的样式; CSS 能够对网页中元素位置的排版进行像素级精确控制,实现美化页面的效果;能够做到页面的样式和 结构分离; 1…...
【MYSQL数据库异常处理】执行SQL语句报超时异常
MYSQL执行SQL语句异常:The last packet successfully received from the server was 100,107 milliseconds ago. The last packet sent successfully to the server was 100,101 milliseconds ago. 这个错误表明 MySQL 服务器与 JDBC 连接之间的通信超时了。通常由…...
【Day9】make/makeFile如何让项目构建自动化起飞
【Day9】make/makeFile如何让项目构建自动化起飞 使用make命令编写makefile文件依赖管理增量构建makefile注释:#makefile其他语法 make/makefile递归式工作过程 在Linux中,项目自动化构建是指使用一系列工具和脚本来自动执行软件项目的编译、测试、打包和…...
【单片机】嵌入式系统的硬件与软件特性
嵌入式系统的软件结构 嵌入式系统的软件结构一般分为 不带操作系统(Bare Metal) 和 带操作系统(RTOS / Linux) 两种。不同的软件架构适用于不同的应用场景,如 简单控制系统、实时控制系统、物联网、工业自动化等。 嵌…...
C语言学习笔记-初阶(30)深入理解指针2
1. 数组名的理解 在上一个章节我们在使用指针访问数组的内容时,有这样的代码: int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址&…...
ROM修改进阶教程------修改安卓机型SELinux宽容的几种方式方法 以及第三方系统中如何关闭SELinux宽容
SELinux是一种强制访问控制安全机制,用于增强Linux系统的安全性。在某些情况下,可能需要对 SELinux 进行宽容设置,以满足特定的应用需求。当SELinux处于宽容模式时,系统允许违反安全策略的行为发生,但不会阻止这些行为,通常会在日志中记录这些违规事件。这与强制模式不同…...
亚马逊云科技Marketplace(中国区)上架专业服务产品, “云生态连接器”价值凸显
近日,由西云数据运营的亚马逊云科技Marketplace(中国区)正式支持专业服务产品。此次发布将大幅简化企业对云专业服务的采购流程,实现云软件从规划、部署到支持的全生命周期管理,同时也为合作伙伴提供了更多的销售机会。…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
