监听 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 就不会重新解码成 / 了,最终也就能达到我们的预期的效果了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/71767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式网络

分布式网络&#xff08;Distributed Network&#xff09;指的是一种计算机网络架构&#xff0c;其中计算资源&#xff08;计算、存储、数据处理等&#xff09;分布在多个物理或逻辑上的节点上&#xff0c;而不是集中在单一的服务器或数据中心中。这种架构的主要目标是提高系统的…

【Elasticsearch】Elasticsearch 中使用 HDFS 存储快照

在 Elasticsearch 中使用 HDFS 存储快照的步骤如下&#xff1a; 1.安装 HDFS 插件 要使用 HDFS 存储 Elasticsearch 的索引快照&#xff0c;需要在 Elasticsearch 集群的所有节点上安装 HDFS 插件。 • 在线安装&#xff1a;适用于网络环境良好的场景&#xff0c;执行以下命…

浅谈 DeepSeek 对 DBA 的影响

引言&#xff1a; 在人工智能技术飞速发展的背景下&#xff0c;DeepSeek 作为一款基于混合专家模型&#xff08;MoE&#xff09;和强化学习技术的大语言模型&#xff0c;正在重塑传统数据库管理&#xff08;DBA&#xff09;的工作模式。通过结合其强大的自然语言处理能力、推理…

STM32F4 UDP组播通信:填一填ST官方HAL库的坑

先说写作本文的原因&#xff0c;由于开项目开发中需要用到UDP组播接收的功能&#xff0c;但是ST官方没有提供合适的参考&#xff0c;使用STM32CubeMX生成的代码也是不能直接使用的&#xff0c;而我在网上找了一大圈&#xff0c;也没有一个能够直接解决的方案&#xff0c;deepse…

leetcode日记(85)验证二叉搜索树

不难&#xff0c;有两种解法&#xff08;看答案才想到中序遍历&#xff09;。 我用的是普通递归&#xff0c;和上一题差不多&#xff0c;规定min和max&#xff0c;每次遍历缩小范围: /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNod…

如何在rust中解析 windows 的 lnk文件(快捷方式)

一、从标题二开始看&#x1f601; 这些天在使用rust写一个pc端应用程序&#xff0c;需要解析lnk文件获取lnk的图标以及原程序地址&#xff0c;之前并没有过pc端应用程序开发的经验&#xff0c; 所以在广大的互联网上游荡了两天。额&#x1f97a; 今天找到了这个库 lnk_parse很…

启动wsl里的Ubuntu24报错:当前计算机配置不支持 WSL2,HCS_E_HYPERV_NOT_INSTALLED

问题&#xff1a;启动wsl里的Ubuntu24报错 报错信息&#xff1a; 当前计算机配置不支持 WSL2。 请启用“虚拟机平台”可选组件&#xff0c;并确保在 BIOS 中启用虚拟化。 通过运行以下命令启用“虚拟机平台”: wsl.exe --install --no-distribution 有关信息&#xff0c;请访…

Python使用FastAPI结合Word2vec来向量化200维的语言向量数值

准备 pip install fastapi>0.68.0 pip install uvicorn[standard]>0.15.0 pip install gensim>4.0.0 pip install jieba>0.42.1 pip install numpy>1.21.0 pip install scikit-learn>1.0.0少了的就直接补充就好 代码 from fastapi import FastAPI, HTTPExc…

ControlNet

文章目录 摘要abstract1.ControlNet1.1 原文摘要1.2 模型架构1.3 架构细节1.4 训练损失函数1.5 实验1.6 结论 2.总结参考文献 摘要 本周学习的ControlNet 是一种用于文本到图像扩散模型&#xff08;如 Stable Diffusion&#xff09;的条件控制方法。它通过冻结预训练的扩散模型…

Visual-RFT视觉强化微调:用「试错学习」教会AI看图说话

&#x1f4dc; 文献卡 英文题目: Visual-RFT: Visual Reinforcement Fine-Tuning;作者: Ziyu Liu; Zeyi Sun; Yuhang Zang; Xiaoyi Dong; Yuhang Cao; Haodong Duan; Dahua Lin; Jiaqi WangDOI: 10.48550/arXiv.2503.01785摘要翻译: 像OpenAI o1这样的大型推理模型中的强化微调…

Hadoop管理页看不到任务的问题

这个yarn分配任务了但是为空 在$HADOOP_HOME/conf/mapred-site.xml 原来的配置文件基础之上添加&#xff1a; <property><name>mapreduce.framework.name</name><value>yarn</value></property> 重启之后就好了

傅里叶变换:跨越时空的数学魔法

引言&#xff1a;从振动到信息——傅里叶的智慧 傅里叶变换&#xff08;Fourier Transform&#xff09;是数学与工程领域最具影响力的工具之一。它的核心思想是将复杂的信号分解为简单的正弦波和余弦波的叠加&#xff0c;从而揭示隐藏在数据背后的频率信息。自19世纪法国数学家…

DR和BDR的选举规则

在 OSPF&#xff08;开放最短路径优先&#xff09;协议中&#xff0c;DR&#xff08;Designated Router&#xff0c;指定路由器&#xff09; 和 BDR&#xff08;Backup Designated Router&#xff0c;备份指定路由器&#xff09; 的选举是为了在广播型网络&#xff08;如以太网…

【linux网络编程】套接字编程API详细介绍

在C语言中&#xff0c;套接字&#xff08;Socket&#xff09;编程主要用于网络通信&#xff0c;尤其是在基于TCP/IP协议的应用程序开发中。常用的套接字编程API主要基于Berkeley Sockets&#xff08;伯克利套接字&#xff09;接口&#xff0c;这些函数通常在<sys/socket.h&g…

Linux和gcc/g++常用命令总结

目录 Linux命令总结 文件操作相关命令 ls cd pwd cp mv rm cat mkdir rmdir touch 文本处理操作命令 grep awk sed 进程管理操作相关命令 ps top htop kill pkill killall chmod chown 网络操作相关命令 ping ifconfig netstat ss lsof curl …

VUE的第二天

1. 指令修饰符 1.1什么是指令修饰符&#xff1f; ​ 所谓指令修饰符就是通过“.”指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码 1.2按键修饰符 keyup.enter —>当点击enter键的时候才触发 代码演示&#xff1a; <div id"app"><…

WSL with NVIDIA Container Toolkit

一、wsl 下安装 docker 会提示安装 docekr 桌面版&#xff0c;所以直接安装 docker 桌面版本即可 二、安装 NVIDIA Container Toolkit NVIDIA Container Toolkit仓库 https://github.com/NVIDIA/nvidia-container-toolkit​github.com/NVIDIA/nvidia-container-toolkit 安装…

mysql下载

目录 下载地址&#xff1a; 1.MSI安装包下载 2.ZIP压缩包下载 卸载MySQL&#xff1a; 下载地址&#xff1a; MySQL :: Download MySQL Community Server到mysql官网进行下载&#xff1a;MySQL :: Download MySQL Community Server &#xff08;下面二选一&#xff0c;选择一…

基于Kubernetes部署MySQL主从集群

以下是一个基于Kubernetes部署MySQL主从集群的详细YAML示例&#xff0c;包含StatefulSet、Service、ConfigMap和Secret等关键配置。MySQL主从集群需要至少1个主节点和多个从节点&#xff0c;这里使用 StatefulSet 初始化脚本 实现主从自动配置。 1. 创建 Namespace (可选) ap…

如何使用 GPT-4o 翻译播客声音

Voice Translation into Different Languages | OpenAI Cookbook 如何使用 GPT-4o 将播客翻译并配音成您的母语 您是否曾想过将播客翻译成您的母语&#xff1f;翻译和配音音频内容可以让全球更多的观众获取信息。而现在&#xff0c;借助 GPT-4o 的音频输入&#xff08;audio-i…