【spring boot】RestTemplate 鏈接帶簽名post請求 400 bad request

由于項目需要從服務端對第三方發起請求,而且第三方沒有提供SDK的情況下,只能根據對方api文檔發送請求了,對方接口的格式是:地址+簽名,post請求上送具體參數的方式去請求對方服務。

背景

很簡單的一個需求,然而開始就卡住了,在Apifox調用能正常返回數據,而一用restTemplate去請求,就報400錯誤。

org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Requestat org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:79)at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122)at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:102)at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:778)at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:736)at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579)
...

Apifox能調通,而代碼調不通,不外乎代碼創建起來的https請求有問題

分析

本來沒打算細究,出錯了打算改用OkHttpClient試一下,還真調通了

    private void action(String uri){OkHttpClient client = new OkHttpClient();RequestBody body = null;body = RequestBody.create(MediaType.parse("application/json"), data);// data是jsonObject轉的String數據Request request = new Request.Builder().url(uri).method("POST", body).addHeader("Content-Type", "application/json").build();try {Response execute = client.newCall(request).execute();System.out.println(execute);} catch (IOException e) {throw new RuntimeException(e);}}

感覺有點離譜,所以直接用抓包工具(這里用的是fiddler,剛學著用,踩了點坑)抓包一下

POST https://xxx/xx/request?AccessKeyId=xxx&Expires=xx&Signature=xxx&Timestamp=2023-12-11T03%253A39%253A36Z HTTP/1.1
Accept: application/json, application/*+json
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_221
Host: xxxxx
Connection: keep-alive
Content-Length: xx{"data":"0"}

返回數據是

HTTP/1.1 400 Bad Request
Date: Mon, 11 Dec 2023 03:39:38 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive9d
{"code":"","message":"日期格式錯誤,請使用yyyy-MM-ddTHH:mm:ssZ格式"}
0

很明顯的錯誤提示“日期格式錯誤,請使用yyyy-MM-ddTHH:mm:ssZ格式”,回頭看下上送的報文是“Timestamp=2023-12-11T03%253A39%253A36Z”,雖然不怎么熟悉url的編碼解碼,但是很明顯%253A實際上是%3A既“:”,所以是因為時間被雙重加密了,因為在拼接url的時候,我已經手動給時間進行了URL編碼

URLEncoder.encode(String.valueOf(time), "UTF-8")

所以去掉后再來

POST https://xxx/xx/request?AccessKeyId=xxx&Expires=xx&Signature=***&Timestamp=2023-12-11T08:25:21Z HTTP/1.1
Accept: application/json, application/*+json
Content-Type: application/json;charset=UTF-8
User-Agent: Java/1.8.0_221
Host: xxxxx
Connection: keep-alive
Content-Length: xx{"data":"0"}

返回數據

HTTP/1.1 401 Unauthorized
Date: Mon, 11 Dec 2023 08:25:21 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive6c
{"error":{"code":"AuthFailure","message":"簽名錯誤"}}
0

玩我呢…我不格式化它也不格式化,只能斷點分析了。發現RestTemplate這里對url進行了處理

	@Override@Nullablepublic <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback,@Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {// 這里getUriTemplateHandler調用了一個默認的處理器對url進行了處理URI expanded = getUriTemplateHandler().expand(url, uriVariables);return doExecute(expanded, method, requestCallback, responseExtractor);}

解決

所以,只要改變這個處理器就可以解決問題了

    @Beanpublic RestTemplate restTemplate(){RestTemplate restTemplate = new RestTemplate();DefaultUriBuilderFactory uriFactory = new DefaultUriBuilderFactory();// 這里選擇了不處理而是自己手動去處理編碼了,所以就不再會出現之前的問題了uriFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);restTemplate.setUriTemplateHandler(uriFactory);// ...return restTemplate;}

總結

很多時候,其實在編碼的時候會下意識自信自己編寫的沒有問題, 以至于在調試的時候很難去發現問題點(開始的時候,其實我先斷點了請求,發現請求是成功出去了,也沒能關注到%253A的問題,一個勁的根據其他文章說的協議、請求頭什么的問題在嘗試),所以當發現問題但又自認為自己沒有問題的時候,不妨換個角度換個方式,或者重新從頭寫一遍(有時候邏輯多的時候,其實也不要怕,一邊寫一邊復盤會比自己只干看著分析還可能好一點)當然具體情況要結合自己實際去行動了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/215315.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/215315.shtml
英文地址,請注明出處:http://en.pswp.cn/news/215315.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Word插件-好用的插件-PPT 素材該怎么積累-大珩助手

PPT 素材該怎么積累&#xff1f; 使用大珩助手中的素材庫功能&#xff0c;將Word中的&#xff0c;或系統中的文本文件、圖片、其他word文檔、pdf&#xff0c;所有見到的好素材&#xff0c;一鍵收納。 步驟&#xff1a;選中文件&#xff0c;按住鼠標左鍵拖到素材庫界面中&…

React-router-dom v6和 v5版本“注冊路由”的差異化

React-router-dom v6和 v5版本“注冊路由”的差異化 Matched leaf route at location “/about” does not have an element. This means it will render an with a null value by default resulting in an “empty” page. v6版本中Switch已經被換成了Routes&#xff0c;點擊鏈…

【軟考】信息系統項目管理師論文方向猜想

報喜不報憂&#xff0c;每天都在為雞零狗碎推諉扯皮&#xff0c;屬實是有辱師門。 通過軟考&#xff0c;目前算是真正有意義的事情。 雖然都說高項的論文是個玄學&#xff0c;但是道聽途說了一些通關感想還是蠻有啟發的。 文件要求 參考了一份廣西省高級工程師評審的文件&am…

Leetcode704二分查找、折半查找(Java實現)

好久沒有更新算法題&#xff0c;今天來寫一道二分查找的題目。題目要求如下&#xff0c; 那么這道題的解題思路如下&#xff0c;我們尋找的過程是首先去訪問數組的中間位置mid&#xff0c;如果nums[mid]大于了targe那么說明&#xff0c;我們要找的數在mid的左半邊&#xff0c;…

IAR開發stm8系列,C語言實現16位乘法器和32位除法器函數

stm8是8位單片機&#xff0c;在ADC采樣采用12bit采樣值進行定點整型運算的時候&#xff0c;為了保證精度需要通過16位乘法器 進行擴大&#xff0c;通過32位除法器縮小運算。但是用c語言直接用“*"和"/"計算是無法實現。c語言的math函數庫也沒有提供這樣的計算函…

CSDN博客遷移至Hexo

實現思路&#xff1a; 獲取博客列表獲取博客詳情解析博客詳情html&#xff0c;找出 #article_content部分通過jsoup解析博客內容&#xff0c;轉成md格式文件 依賴 <dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</art…

Linux實用操作篇-下篇

Linux實用操作篇-上篇&#xff1a;Linux實用操作-上篇-CSDN博客 一、網絡傳輸 1.1 ping命令 網絡是否可聯通 可以通過ping命令&#xff0c;檢查指定的網絡服務器是否是可聯通狀態 語法: ping [-c num] ip或主機名 選項&#xff1a;-c&#xff0c;檢查的次數&#xff0c;…

嵌入式SOC芯片選型

摘要&#xff1a; 本文主要探討的是如果涉及芯片選型&#xff0c;需要考慮哪些方面&#xff1f; 將相關的需求列出來&#xff0c;供后續實踐的時候參考。 SOC芯片選型 能力參數指標備注算力編碼能力VPU處理能力YUV算法資源媒體audiovideoCPU運行主頻架構DDRDDR規格DDR帶寬DD…

cmake常用設置命令及參數大全

CMake是一個跨平臺的開源構建工具,用于管理軟件項目的構建過程。它使用簡單的配置文件(CMakeLists.txt)來定義構建過程的規則。 以下是一些常用的CMake設置和命令: 1. cmake_minimum_required(VERSION x.x):指定需要的CMake版本。 2. project(project_name):設置項目的…

深入理解Java虛擬機---垃圾收集算法

深入理解Java虛擬機---垃圾收集算法 如何判定對象是否存活引用計數法可達性分析法 Java引用類型垃圾回收算法標記-清除算法復制算法標記-整理算法分代收集算法 HotSpot的算法實現枚舉根節點安全點安全區域 如何判定對象是否存活 引用計數法 引用計數算法利用額外的內存空間來…

Dockerfile創建鏡像介紹

1.介紹 Docker 提供了一種更便捷的方式&#xff0c;叫作 Dockerfile&#xff0c;docker build命令用于根據給定的Dockerfile構建Docker鏡像。 docker build語法&#xff1a; # docker build [OPTIONS] <PATH | URL | -> 常用選項說明 --build-arg&#xff0c;設置構建時的…

上海亞商投顧:滬指探底回升 AI應用方向再度爆發

上海亞商投顧前言&#xff1a;無懼大盤漲跌&#xff0c;解密龍虎榜資金&#xff0c;跟蹤一線游資和機構資金動向&#xff0c;識別短期熱點和強勢個股。 一.市場情緒 三大指數昨日探底回升&#xff0c;早盤一度均跌超1%&#xff0c;午后集體拉升翻紅&#xff0c;深成指、創業板…

FFmpeg的AVcodecParser

文章目錄 結構體操作函數支持的AVCodecParser 這個模塊是AVCodec中的子模塊&#xff0c;專門用來提前解析碼流的元數據&#xff0c;為后面的解碼做準備&#xff0c;這一點對cuda-NVdec非常明顯&#xff0c;英偉達解碼器的元數據解析是放在CPU上的&#xff0c;所以就非常依賴這個…

為什么Vue3的proxy需要Reflect呢

何為proxy Proxy 對象用于定義或修改某些操作的自定義行為&#xff0c;可以在外界對目標對象進行訪問前&#xff0c;對外界的訪問進行改寫。 var proxy new Proxy(target, handler)ES6 中的proxy目前提供了13種可代理操作攔截的行為。 何為reflect ES6 標準中&#xff0c;…

遠程工作:自由職業者如何成功賺錢

前言 在這個不斷進步的數字化時代&#xff0c;遠程工作已經從一個可選的邊緣工作方式&#xff0c;成長為主流職業趨勢的一部分。特別是自從全球疫情改變了我們的生活和工作方式以來&#xff0c;遠程工作的概念不再是遙不可及的理想&#xff0c;而是已經成為許多人日常工作的現…

SpringBoot集成swagger2配置權限認證參數

作者簡介&#xff1a;大家好&#xff0c;我是擼代碼的羊駝&#xff0c;前阿里巴巴架構師&#xff0c;現某互聯網公司CTO 聯系v&#xff1a;sulny_ann&#xff08;17362204968&#xff09;&#xff0c;加我進群&#xff0c;大家一起學習&#xff0c;一起進步&#xff0c;一起對抗…

[Java][JDK5]可變參數

我們可以假設一種情況&#xff0c;我們需要進行求和計算 在原先&#xff0c;我們考慮到參數只能傳入一個數字&#xff0c;因此我們會將需要求和的數字放在一個數組&#xff0c;傳入該數組進入方法再拆分計算 比如下面的例子:使用了增強for來對數組進行遍歷 public class Mai…

【Lidar】基于Python的三維點云數據轉二維平面+散點圖繪制

最近一直在搞點云相關的操作&#xff0c;有時候在處理點云數據時需要查看處理后的數據是否滿足需求&#xff0c;所以就想著寫一套展示點云的代碼。之前已經分享過如何可視化點云了&#xff0c;感興趣的可以自己去看下&#xff1a;【Lidar】基于Python的Open3D庫可視化點云數據。…

golang https server如何設計方便抓包定位且安全

代碼 測試 用go寫后端https服務時&#xff0c;需要定位https包中的內容是否符合預期。 有涉獵的朋友應該了解過https有一種keylog技術&#xff0c;它允許在HTTPS連接中捕獲和記錄SSL或TLS會話密鑰&#xff0c;以便于調試和分析加密流量。 本文將的就是通過可控制開啟和關閉的…

單身狗(Python)

題目描述 單身狗 “單身狗”是中文對于單身人士的一種愛稱。本題請你從上萬人的大型派對中找出落單的客人&#xff0c;以便給予特殊關愛。 輸入格式&#xff1a; 輸入第一行給出一個正整數 N&#xff08;≤50000&#xff09;&#xff0c;是已知夫妻/伴侶的對數&#xff1b;…