監聽 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.pswp.cn/pingmian/71767.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/71767.shtml
英文地址,請注明出處:http://en.pswp.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…