最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java調(diào)用UniHttp接口請(qǐng)求失敗的三種解決策略

 更新時(shí)間:2025年09月15日 09:19:05   作者:夜郎king  
在當(dāng)今數(shù)字化時(shí)代,不管是內(nèi)部系統(tǒng)之間還是跟外部系統(tǒng)的對(duì)接,接口調(diào)用已成為軟件開發(fā)中不可或缺的一部分,本文主要介紹了Java調(diào)用UniHttp接口請(qǐng)求失敗的三種解決策略,希望對(duì)大家有所幫助

前言

在當(dāng)今數(shù)字化時(shí)代,不管是內(nèi)部系統(tǒng)之間還是跟外部系統(tǒng)的對(duì)接,接口調(diào)用已成為軟件開發(fā)中不可或缺的一部分。Java作為一種廣泛使用的編程語言,在接口調(diào)用方面有著豐富的應(yīng)用。在現(xiàn)代軟件架構(gòu)中,分布式系統(tǒng)和微服務(wù)架構(gòu)的廣泛應(yīng)用使得不同模塊之間的通信主要依賴于接口調(diào)用。在之前的博文中,我們講解了許多跟第三方接口對(duì)接的詳細(xì)案例,比如如何調(diào)用實(shí)時(shí)航班數(shù)據(jù)、接入百度地圖、高德地圖、天地圖、實(shí)時(shí)景區(qū)等多源數(shù)據(jù),也講解了一些數(shù)據(jù)接入方式,比如使用抓取器,也詳細(xì)敘述過UniHttp框架來進(jìn)行接口調(diào)用。如果是一些對(duì)請(qǐng)求參數(shù)順序沒有限制的接口中,一般來講是可以正常進(jìn)行集成的,而在一些需要二次驗(yàn)簽的接口,比如一些在線地圖的開放平臺(tái)中就可以支持二次驗(yàn)簽,以百度地圖為例,需要二次驗(yàn)簽的接口接入流程如下圖所示:

通過上圖可以直觀的看到,二次驗(yàn)簽可以很好的對(duì)請(qǐng)求進(jìn)行保護(hù),用戶可以隨時(shí)修改二次驗(yàn)簽的密鑰,這樣即使是不小心泄露了AK,也可以很好的避免AK的濫用,客戶端需要使用sk進(jìn)行參數(shù)驗(yàn)簽,然后生成驗(yàn)簽參數(shù),服務(wù)端會(huì)使用同樣的sk來進(jìn)行同樣的參數(shù)驗(yàn)證,如果匹配則放行,否則會(huì)拒絕訪問,返回驗(yàn)證失敗。在實(shí)際開發(fā)過程中,開發(fā)者們常常會(huì)遇到各種問題,其中請(qǐng)求參數(shù)亂序?qū)е陆涌谡{(diào)用失敗便是較為常見的一種。百度SN簽名認(rèn)證是一種常見的接口認(rèn)證方式,它通過在請(qǐng)求中添加特定的簽名參數(shù)來驗(yàn)證請(qǐng)求的合法性。在進(jìn)行接口調(diào)用時(shí),請(qǐng)求參數(shù)的順序?qū)τ诤灻纳芍陵P(guān)重要。如果參數(shù)順序發(fā)生混亂,生成的簽名將與服務(wù)器端的預(yù)期不一致,從而導(dǎo)致接口請(qǐng)求被拒絕。請(qǐng)求參數(shù)亂序問題雖然看似微不足道,但實(shí)際上可能會(huì)給開發(fā)工作帶來巨大的困擾。首先,它會(huì)導(dǎo)致接口調(diào)用失敗,使得開發(fā)進(jìn)度受阻。開發(fā)者需要花費(fèi)大量時(shí)間排查問題,尋找導(dǎo)致亂序的原因。其次,這個(gè)問題可能會(huì)引發(fā)安全風(fēng)險(xiǎn)。如果簽名認(rèn)證機(jī)制被破壞,可能會(huì)導(dǎo)致未經(jīng)授權(quán)的訪問,從而威脅到系統(tǒng)的安全性和穩(wěn)定性。因此,解決請(qǐng)求參數(shù)亂序問題對(duì)于確保接口調(diào)用的成功和系統(tǒng)的安全性至關(guān)重要。

本文將以百度SN簽名認(rèn)證為例,深入探討在Java調(diào)用UniHttp接口時(shí),如何解決請(qǐng)求參數(shù)亂序問題,以確保接口請(qǐng)求的成功。在解決問題的同時(shí),也跟開源作者進(jìn)行了咨詢,得到了作者的指導(dǎo),對(duì)于問題的解決幫助非常大,因此在這里也簡單講講與開源作者的交流過程及啟發(fā)。

一、場景重現(xiàn)

本節(jié)將詳細(xì)介紹使用UniHttp模式下,接入第三方接口是,遇到SN的驗(yàn)簽方式時(shí)會(huì)遇到驗(yàn)證失敗的問題。通過重現(xiàn)接口調(diào)用現(xiàn)場,讓大家對(duì)發(fā)生問題的背景有一個(gè)基本的認(rèn)識(shí),也為后面解決問題留下思考的空間。本節(jié)將從以下三個(gè)方面去講解,首先我們按照普通的模式來進(jìn)行UniHttp接口的接口定義,然后詳細(xì)介紹SN模式的接口正式調(diào)用,最后詳細(xì)說明可能遇到的問題。如果大家在使用UniHttp時(shí)沒有遇到認(rèn)證問題,那真的恭喜你,可以劃走了。如果您也身處迷茫之中,不妨來這里看看。

1、UniHttp模式下SN接口定義

我們首先按照官方文檔的文檔說明,在UniHttp中進(jìn)行百度搜索接口的調(diào)用。按照UniHttp的處理請(qǐng)求規(guī)范,定義第一版的請(qǐng)求接口,接口定義如下:

package com.yelang.project.thridinterface;
import com.burukeyou.uniapi.http.annotation.HttpApi;
import com.burukeyou.uniapi.http.annotation.param.QueryPar;
import com.burukeyou.uniapi.http.annotation.request.GetHttpInterface;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
@HttpApi
public interface BaiduGeoSearchWithSnService {
	/**
	 * - 百度行政區(qū)劃區(qū)域檢索接口
	 * @param query         檢索關(guān)鍵字。行政區(qū)劃區(qū)域檢索不支持多關(guān)鍵字檢索。如果需要按POI分類進(jìn)行檢索,請(qǐng)將分類通過query參數(shù)進(jìn)行設(shè)置,如query=美食
	 * @param region        檢索行政區(qū)劃區(qū)域(增加區(qū)域內(nèi)數(shù)據(jù)召回權(quán)重,如需嚴(yán)格限制召回?cái)?shù)據(jù)在區(qū)域內(nèi),請(qǐng)搭配使用city_limit參數(shù)),可輸入行政區(qū)劃名或?qū)?yīng)
	 * @param output        輸出格式為json或者xml
	 * @param scope         檢索結(jié)果詳細(xì)程度。取值為1 或空,則返回基本信息;取值為2,返回檢索POI詳細(xì)信息
	 * @param ret_coordtype 返回的坐標(biāo)類型,可選參數(shù),添加后POI返回國測局經(jīng)緯度坐標(biāo)
	 * @param pageSize      單次召回POI數(shù)量,默認(rèn)為10條記錄,最大返回20條
	 * @param pageNum       分頁頁碼,默認(rèn)為0,0代表第一頁
	 * @param ak            開發(fā)者的訪問密鑰,必填項(xiàng)
	 * @param sn            開發(fā)者的權(quán)限簽名
	 * @return
	 */
	@GetHttpInterface(url="https://api.map.baidu.com/place/v2/search")
	public HttpResponse<String> getSearch(@QueryPar("query") String query, @QueryPar("region") String region,
			@QueryPar("output") String output, @QueryPar("scope") String scope,
			@QueryPar("ret_coordtype") String ret_coordtype, @QueryPar("page_size") int pageSize,
			@QueryPar("page_num") int pageNum, @QueryPar("ak") String ak, @QueryPar("sn") String sn);
}

與普通的接口請(qǐng)求一樣,這里按照官方文檔要求,這里只增加一個(gè)sn的簽名參數(shù)。在調(diào)用的時(shí)候動(dòng)態(tài)傳入sn參數(shù)實(shí)現(xiàn)接口的調(diào)用。

2、第一次正式調(diào)用

接下來還是常規(guī)操作,我們使用Junit來進(jìn)行接口的測試,使用UniHttp來代理服務(wù)訪問之后,接口的調(diào)用就比較簡單了。直接在測試類中注入service實(shí)例后就可以進(jìn)行服務(wù)的調(diào)用,關(guān)鍵代碼如下:

package com.yelang.project.unihttp;
import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
import com.yelang.project.thridinterface.BaiduGeoSearchSnProcessorService;
import com.yelang.project.thridinterface.BaiduGeoSearchWithSnService;
import com.yelang.project.thridinterface.signature.BaiduSignature;
/**
 * - 百度檢索2.0接口帶SN訪問服務(wù)示例
 * @author 夜郎king
 *
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class BaiduGeoSearchWithSnServiceCase {
	/**
	 * - 應(yīng)用申請(qǐng)的AK值
	 */
	private static final String AK_VALUE = "yourak";
	/**
	 * - 應(yīng)用申請(qǐng)的SK值
	 */
	private static final String SK_VALUE = "yoursk";
	@Autowired
	private BaiduGeoSearchWithSnService bdGeoSearchWithSnService;
	@Test
	public void searchBySn() throws UnsupportedEncodingException {
		/**
		 * -計(jì)算sn跟參數(shù)對(duì)出現(xiàn)順序有關(guān),get請(qǐng)求請(qǐng)使用LinkedHashMap保存<key,value>,該方法根據(jù)key的插入順序排序;
		 * -post請(qǐng)使用TreeMap保存<key,value>,該方法會(huì)自動(dòng)將key按照字母a-z順序排序。
		 * -所以get請(qǐng)求可自定義參數(shù)順序(sn參數(shù)必須在最后)發(fā)送請(qǐng)求,但是post請(qǐng)求必須按照字母a-z順序填充body(sn參數(shù)必須在最后)。
		 * -以get請(qǐng)求為例:https://api.map.baidu.com/geocoder/v2/?address=百度大廈&output=json&ak=yourak,paramsMap中先放入address,
		 * -再放output,然后放ak,放入順序必須跟get請(qǐng)求中對(duì)應(yīng)參數(shù)的出現(xiàn)順序保持一致。
		 */
		Map<String, String> paramsMap = new LinkedHashMap<String, String>();
		String api_prefix = "/place/v2/search?";
		//按接口定義順序來創(chuàng)建參數(shù)
		String query = "湘菜";
		String region = "158";// 158表示長沙市
		String output = "json";
		String scope = "2";
		String ret_coordtype = "WGS84";
		int pageSize = 20;
		int pageNum = 0;
		paramsMap.put("query", query);
		paramsMap.put("region", region);
		paramsMap.put("output", output);
		paramsMap.put("scope", scope);
		paramsMap.put("ret_coordtype", ret_coordtype);
		paramsMap.put("page_size", String.valueOf(pageSize));
		paramsMap.put("page_num", String.valueOf(pageNum));
		paramsMap.put("ak", AK_VALUE);
		// 調(diào)用簽名工具生成SN
		BaiduSignature signature = new BaiduSignature(AK_VALUE, SK_VALUE,paramsMap,api_prefix);
		String sn = signature.getSnByMap();
		System.out.println("sn==>" + sn);
		HttpResponse<String> result = bdGeoSearchWithSnService.getSearch(query, region, output, scope,
				ret_coordtype, pageSize, pageNum ,AK_VALUE,sn);
		System.out.println("第一頁的數(shù)據(jù)如下:");
		System.out.println(result);
		System.out.println(result.getBodyResult());
		System.out.println("--------------------------------------------------------------");
	}
}

在這里請(qǐng)注意,這里我們進(jìn)行接口定義時(shí),按照上層接口的定義時(shí)參數(shù)的有序性,我們?cè)谠O(shè)置HashMap時(shí)使用的是LinkedHashMap來進(jìn)行保存,讓生成SN值的時(shí)候按照順序來生成。萬事俱備只欠東風(fēng),下面我們就可以直接運(yùn)行調(diào)用函數(shù),來測試一下接口是否可以聯(lián)通。

3、第一次遇到211 APP SN校驗(yàn)失敗

通常來說,不出意外的話一定是出了意外。我們本來是充滿了希望,認(rèn)為直接將參數(shù)傳入到UniHttp中進(jìn)行攜帶訪問即可,先來看下運(yùn)行之后,在控制臺(tái)中看到以下結(jié)果,如下圖:

首輪宣告失敗,這是我們第一次遇到:{"status":211,"message":"APP SN校驗(yàn)失敗"}。當(dāng)然這個(gè)錯(cuò)誤我們?cè)谥暗牟┛椭性?jīng)簡單介紹過,在官方文檔中也有所提及。如下表:

211APP SN校驗(yàn)失敗SERVER類型APP有兩種校驗(yàn)方式IP校驗(yàn)和SN校驗(yàn),當(dāng)用戶請(qǐng)求的SN和服務(wù)端計(jì)算出來的SN不相等的時(shí)候提示SN校驗(yàn)失敗

出現(xiàn)SN校驗(yàn)失敗的原因就是服務(wù)端的SN值和客戶端計(jì)算的值不一樣,導(dǎo)致不一樣的可能有很多種,比如參數(shù)值順序,還有就是ak和sk的值有變化,這些都是有可能的。那么使用UniHttp請(qǐng)求框架后,為什么會(huì)遇到這種問題呢?下面將針對(duì)這個(gè)問題來進(jìn)行問題定位。

二、問題查找及開源尋求解決方案

程序開發(fā)的過程就是解決問題的過程,遇到請(qǐng)求不通的情況確實(shí)比較容易讓人焦急,但是如果能解決問題,那么自己又能積累更多的實(shí)戰(zhàn)經(jīng)驗(yàn)。遇到問題,我們根據(jù)官網(wǎng)的提示來大膽的猜測問題,即SN的計(jì)算生成問題,究竟是哪里出了問題?上面也分析了一些原因,比如參數(shù)的順序等。既然是開源項(xiàng)目,我們就可以通過源碼的定位來分析問題,也可以通過debug調(diào)試代碼來進(jìn)行輔助。

本節(jié)分享博主如何抽絲剝繭的進(jìn)行問題分析,最終找到了問題的所在。接著帶著問題,通過GitHub上找到了開源作者,并且做了一些交流,通過信息的分享,進(jìn)一步明確了問題的所在,從而解決了問題。這是一個(gè)特別有趣的過程,在與開源作者的溝通過程中,也能看到開源作者身上的韌勁和開源精神。

1、抽絲剝繭找到問題所在

既然是參數(shù)生成的問題,那么我們就首先使用Debug的方式來看看到底是發(fā)生了什么?根據(jù)之前的經(jīng)驗(yàn),我們懷疑是請(qǐng)求參數(shù)的順序的問題。因此我們可以在Eclipse中使用Debug的方式來看一下請(qǐng)求的參數(shù)順序到底有沒有問題,請(qǐng)求參數(shù)我們可以在HttpResponse對(duì)象中的值中進(jìn)行獲取,UniHttpResponse中可以看到:

在HttpUrl對(duì)象中可以看到請(qǐng)求的地址和請(qǐng)求的參數(shù),進(jìn)一步打開這個(gè)HttpUrl對(duì)象的值:

HttpUrl(
url=https://api.map.baidu.com/place/v2/search?, 
path=, 
anchor=null, 
queryParam={output=json, query=湘菜, scope=2, page_num=0, ak=yourak, s
n=d1abf338a49bd82fca6992f5d2b9f686, 
region=158, ret_coordtype=WGS84, 
page_size=20}, 
pathParam={}
)

請(qǐng)注意,上面參數(shù)中queryParam與我們?cè)诮涌谥卸x的順序似乎不太一樣,為了方便對(duì)比,我們整理成以下圖片表格:

可以看到在請(qǐng)求發(fā)送過程中,經(jīng)過UniHttp的處理,參數(shù)的順序已經(jīng)發(fā)生了變化,因此可以得出結(jié)論,在請(qǐng)求過程中參數(shù)的順序發(fā)生了變化,由此發(fā)生的請(qǐng)求,服務(wù)端拿到請(qǐng)求參數(shù)后,根據(jù)這個(gè)參數(shù)去加密計(jì)算得到的SN,與我們自己計(jì)算的一定是不一樣的,所以就會(huì)發(fā)生SN驗(yàn)證失敗的問題?,F(xiàn)在基本是可以定位是這個(gè)問題。帶著疑問我們就這個(gè)開源項(xiàng)目跟作者試著聊一聊。

2、與作者在Issues的交流

帶著問題,打開開源項(xiàng)目的開源地址,UniHttp開源地址。首先我們來看一下有關(guān)這個(gè)項(xiàng)目的Issues,或許在我之前已經(jīng)有朋友遇到類似的問題,來看下列表界面:

可以看到暫時(shí)還沒有其它的博主有類似的問題,第一條其實(shí)博主本人與開源作者的實(shí)際交流情況。點(diǎn)開交流詳情,是我們的詳細(xì)交流過程:

博主在Issue中描述了個(gè)人的使用問題和疑問,并咨詢了作者是否可以設(shè)置順序問題。也是非??焖俚牡玫搅俗髡叩幕貜?fù)

雖然在官方文檔中看到,也親自實(shí)踐過這個(gè)方法,但是還是得為作者的迅速點(diǎn)贊。因?yàn)檎娴臎]有多久就得到了作者本文的回復(fù)。

3、開源項(xiàng)目交流有感

UniHttp這個(gè)項(xiàng)目非常好用,在服務(wù)接口接入中提供了非常良好的便利性。也因此,使用的朋友非常多。在博主遇到相關(guān)的請(qǐng)求參數(shù)亂序的情況下,及時(shí)找到了開源地址,并且給予了留言說明了詳細(xì)情況。中所周知,開源項(xiàng)目一般都是自己的副業(yè)或者第二職業(yè),并不是隨時(shí)隨地的要看開源社區(qū)的消息和問題。但是這次的問題反饋和交流,卻是異常的迅速,同時(shí)開源作者也指出了解決方法和實(shí)現(xiàn)路徑。這是個(gè)人遇到的答復(fù)非常迅速及時(shí)的開源項(xiàng)目了,上一個(gè)如此迅速的項(xiàng)目是kkfileview。開源不易,希望大家都能找到解決辦法,也能貢獻(xiàn)更多的好項(xiàng)目,以后會(huì)更加深入的加入開源項(xiàng)目,為開源做貢獻(xiàn)。

三、朝著正確的方向解決問題

言歸正傳,在開源作者的指導(dǎo)下,我們又回到問題的本身,既然是參數(shù)的問題,那么我們?nèi)绾蝸斫鉀Q呢?找到了正確的方向,接下來就是朝著正確的方向去努力,去找到解決的辦法。這里我們按照從簡單到復(fù)雜,從固化到靈活的三種不同的解決辦法,如果還有更好的方法,也歡迎各位專家、博主在評(píng)論區(qū)指出。

1、加密順序按實(shí)際請(qǐng)求參數(shù)求解

首先分享第一種比較簡單的方法,已經(jīng)知道導(dǎo)致驗(yàn)證失敗的原因就是參數(shù)不一致的原因。在UniHttp中,使用以下方式定義的接口:

@GetHttpInterface(url="https://api.map.baidu.com/place/v2/search")
public HttpResponse<String> getSearch(@QueryPar("query") String query, @QueryPar("region") String region,
			@QueryPar("output") String output, @QueryPar("scope") String scope,
			@QueryPar("ret_coordtype") String ret_coordtype, @QueryPar("page_size") int pageSize,
			@QueryPar("page_num") int pageNum, @QueryPar("ak") String ak, @QueryPar("sn") String sn);

通常隨著參數(shù)的定義完成之后,其請(qǐng)求參數(shù)的順序基本就可以預(yù)估了,因此第一種方式實(shí)際上比較簡單,在客戶端加密的時(shí)候,把參數(shù)順序按照服務(wù)端的加密順序進(jìn)行處理,服務(wù)端的加密加密順序我們可以使用上一節(jié)中的方式進(jìn)行Debug時(shí)進(jìn)行跟蹤。根據(jù)請(qǐng)求的參數(shù)順序做如下調(diào)整:

@Test
public void searchBySn() throws UnsupportedEncodingException {
	Map<String, String> paramsMap = new LinkedHashMap<String, String>();
	String api_prefix = "/place/v2/search?";
	/*
	 * - 按請(qǐng)求順序來加密
	*/
	String output = "json";
	String query = "湘菜";
	String scope = "2";
	int pageNum = 0;
	String region = "158";// 158表示長沙市
	String ret_coordtype = "WGS84";
	int pageSize = 20;
	paramsMap.put("output", output);
	paramsMap.put("query", query);
	paramsMap.put("scope", scope);
	paramsMap.put("page_num", String.valueOf(pageNum));
	paramsMap.put("ak", AK_VALUE);
	paramsMap.put("region", region);
	paramsMap.put("ret_coordtype", ret_coordtype);
	paramsMap.put("page_size", String.valueOf(pageSize));
	// 調(diào)用簽名工具生成SN
	BaiduSignature signature = new BaiduSignature(AK_VALUE, SK_VALUE,paramsMap,api_prefix);
	String sn = signature.getSnByMap();
	System.out.println("sn==>" + sn);
	HttpResponse<String> result = bdGeoSearchWithSnService.getSearch(query, region, output, scope,
				ret_coordtype, pageSize, pageNum ,AK_VALUE,sn);
	System.out.println("第一頁的數(shù)據(jù)如下:");
	System.out.println(result);
	System.out.println(result.getBodyResult());
	System.out.println("--------------------------------------------------------------");
}

再次運(yùn)行程序發(fā)現(xiàn)成功獲取了數(shù)據(jù):

上面這種方式雖然可以解決問題,但是每次都需要進(jìn)行調(diào)整參數(shù),使用起來比較麻煩,下面我們根據(jù)作者的推薦使用請(qǐng)求前置處理器來進(jìn)行參數(shù)的重新設(shè)置。

2、一種兼容Get請(qǐng)求參數(shù)動(dòng)態(tài)調(diào)整的方法

關(guān)于使用Processor的模式來進(jìn)行請(qǐng)求參數(shù)重置的方法雖然是第一次說,但是之前我們講過基于Processor的AK自動(dòng)設(shè)置,其核心原理是差不多的。這里我們的改造重點(diǎn)是BaiduHttpApiProcessor中的postBeforeHttpRequest方法。這個(gè)方法的核心作用就是發(fā)送Http請(qǐng)求之前會(huì)回調(diào)該方法,可對(duì)Http請(qǐng)求體的內(nèi)容進(jìn)行二次處理。因此我們首先直接來拼接請(qǐng)求參數(shù)的方法。在這里我們需要完全重寫請(qǐng)求URL,以完成全新的請(qǐng)求。根據(jù)queryParams來重新拼接請(qǐng)求字符串,我們從queryParams中取出請(qǐng)求集合,然后根據(jù)Map再設(shè)置Url的值,核心方法如下:

/**
* 
* @param snMapParams
* @param queryParam
* @return
*/
protected Map<String, Object> reorderingQueryParamMap(String snMapParams,Map<String, Object> queryParam) {
	Map<String, Object> paramsMap = null;
	if(StringUtils.isNotEmpty(snMapParams)) {
		paramsMap = new LinkedHashMap<String, Object>();
		//將ak和sn分別放到paramsMap中
		paramsMap.put("region", queryParam.get("region"));
        //其它參數(shù)
		//將ak和sn分別放到paramsMap中
		paramsMap.put("ak", queryParam.get("ak"));
		paramsMap.put("sn", queryParam.get("sn"));
	}else {
		paramsMap = queryParam;
	}
	return paramsMap;
}

在請(qǐng)求之前手動(dòng)修改URL地址,關(guān)鍵方法如下:

/** * -實(shí)現(xiàn)-postBeforeHttpMetadata: 發(fā)送Http請(qǐng)求之前會(huì)回調(diào)該方法,可對(duì)Http請(qǐng)求體的內(nèi)容進(jìn)行二次處理
*
* @param uniHttpRequest              原來的請(qǐng)求體
* @param methodInvocation          被代理的方法
* @return                          新的請(qǐng)求體
*/
@Override
public UniHttpRequest postBeforeHttpRequest(UniHttpRequest uniHttpRequest,
			HttpApiMethodInvocation<BaiduHttpApi> methodInvocation) {
		/**
         * -在查詢參數(shù)中添加提供的appId字段
         */
        // 獲取BaiduHttpApi注解
		BaiduHttpApi apiAnnotation = methodInvocation.getProxyApiAnnotation();
        // 獲取所有查詢參數(shù)
        Map<String, Object> queryParam = uniHttpRequest.getHttpUrl().getQueryParam();
        System.out.println("未處理之前的請(qǐng)求參數(shù):" + queryParam);
        Map<String, Object> paramsMap = this.reorderingQueryParamMap(snMapParams, queryParam);
       System.out.println("處理之后的請(qǐng)求參數(shù):" + paramsMap);
        // 第二種方式,直接修改請(qǐng)求參數(shù)
        String queryString =  this.reorderingQueryParam(snMapParams,queryParam);
        uniHttpRequest.getHttpUrl().setQueryParam(null);
        String url = uniHttpRequest.getHttpUrl().getUrl() + uniHttpRequest.getHttpUrl().getPath() + "?" + queryString;
        uniHttpRequest.getHttpUrl().setUrl(url);
        uniHttpRequest.getHttpUrl().setPath("");
    }
    return uniHttpRequest;
}

請(qǐng)注意,使用這種方式,一般需要將QueryParam參數(shù)這是為空,并且完全使用url參數(shù),不要使用path,可以直接設(shè)置為null即可。還有使用方式的時(shí)候需要注意的點(diǎn),即我們的接口定義時(shí),不要多加?號(hào),否則會(huì)變成雙問號(hào),從而導(dǎo)致請(qǐng)求報(bào)錯(cuò),比如:

@GetHttpInterface(path = "/place/v2/search?")
public HttpResponse<String> getSearch(@QueryPar("query") String query, @QueryPar("region") String region,
			@QueryPar("output") String output, @QueryPar("scope") String scope,
			@QueryPar("ret_coordtype") String ret_coordtype, @QueryPar("page_size") String pageSize,
			@QueryPar("page_num") String pageNum, @QueryPar("ak") String ak, @QueryPar("sn") String sn);

加完之后,再查看UniHttp發(fā)出的請(qǐng)求地址就會(huì)加了一個(gè)?號(hào),如下圖:

將請(qǐng)求地址復(fù)制出來,

url=https://api.map.baidu.com/place/v2/search??query=%E6%B9%98%E8%8F%9C&region=158&output=json&scope=2&ret_coordtype=WGS84&page_size=20&page_num=0&ak=yourak&sn=d1abf338a49bd82fca6992f5d2b9f686

由此也會(huì)極易導(dǎo)致出現(xiàn)SN校驗(yàn)失敗的問題,請(qǐng)大家注意。

3、使用注解來設(shè)置重排序規(guī)則

沒有什么方法是可以自己來定義請(qǐng)求的請(qǐng)求順序呢?答案是一定的,我們完全可以將參數(shù)的順序定義到注解中,同時(shí)增加一個(gè)SN校驗(yàn)的模式開關(guān),這樣程序?qū)崿F(xiàn)起來就更加靈活。在注解類中作如下定義:

package com.yelang.project.thridinterface.apiprocessor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import com.burukeyou.uniapi.http.annotation.HttpApi;
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@HttpApi(processor = BaiduHttpApiProcessor.class)
public @interface BaiduHttpApi {
	/**
     * -渠道方域名地址
     */
    @AliasFor(annotation = HttpApi.class)
    String url() default "${unihttp.channel.baidu.url}";
    /**
     * -snMapParams 模式下的請(qǐng)求參數(shù)順序,用于按順序加密,在統(tǒng)一處理器中獲取后處理
     */
    String snMapParams() default "";
    /**
     * - 是否使用sn簽名模式
     * @return
     */
    boolean snMode() default false;
}

重點(diǎn)就是這兩個(gè)參數(shù),通過這兩個(gè)參數(shù)來設(shè)置SN模式和具體的參數(shù),定義了注解字后,我們看在Processor中如何使用。簡單來說就是先看SN模式,然后再解析參數(shù)設(shè)置的順序,再讀取參數(shù)放置到集合中或者拼接到字符串中。核心方法如下:

/**
* 
* @param snMapParams
* @param queryParam
* @return
*/
protected Map<String, Object> reorderingQueryParamMap(String snMapParams,Map<String, Object> queryParam) {
	Map<String, Object> paramsMap = null;
	if(StringUtils.isNotEmpty(snMapParams)) {
		paramsMap = new LinkedHashMap<String, Object>();
		//從注解中讀取配置的參數(shù)
		String [] snMap = snMapParams.split(",");
		//按照參數(shù)重新組合參數(shù),生成按順序的請(qǐng)求字符串
		for(String paramKey : snMap) {
			paramsMap.put(paramKey, queryParam.get(paramKey));
		}
		//將ak和sn分別放到paramsMap中
		paramsMap.put("ak", queryParam.get("ak"));
		paramsMap.put("sn", queryParam.get("sn"));
	}else {
		paramsMap = queryParam;
	}
	return paramsMap;
}

這樣通過結(jié)合注解方式來實(shí)現(xiàn)了參數(shù)順序的定義,在創(chuàng)建接口時(shí)注意注解的設(shè)置,實(shí)例如下,通過設(shè)置參數(shù)就設(shè)置了運(yùn)行模式:

@BaiduHttpApi(snMode = true, snMapParams = "query,region,output,scope,ret_coordtype,page_size,page_num")
public interface BaiduGeoSearchSnProcessorService {
}

4、重寫請(qǐng)求的QueryParam重排序方法

這里結(jié)合前面的注記方式來對(duì)請(qǐng)求參數(shù)的重排序進(jìn)行處理,這種方式適應(yīng)性更加強(qiáng)。與get方式不同的是,使用設(shè)置queryParam的方式,程序的通用性和方法的兼容性會(huì)更加好。重新設(shè)置QueryParam的方法核心代碼如下:

/** * -實(shí)現(xiàn)-postBeforeHttpMetadata: 發(fā)送Http請(qǐng)求之前會(huì)回調(diào)該方法,可對(duì)Http請(qǐng)求體的內(nèi)容進(jìn)行二次處理
 *
 * @param uniHttpRequest              原來的請(qǐng)求體
 * @param methodInvocation          被代理的方法
 * @return                          新的請(qǐng)求體
 */
@Override
public UniHttpRequest postBeforeHttpRequest(UniHttpRequest uniHttpRequest,
			HttpApiMethodInvocation<BaiduHttpApi> methodInvocation) {
    // 獲取BaiduHttpApi注解
	BaiduHttpApi apiAnnotation = methodInvocation.getProxyApiAnnotation();
    String snMapParams = apiAnnotation.snMapParams();
    boolean snMode = apiAnnotation.snMode();
    //如果開啟sn簽名,則將請(qǐng)求參數(shù)進(jìn)行充排序后進(jìn)行簽名,反之不用處理
    if(snMode) {
        System.out.println("開啟SN簽名處理");
        // 獲取所有查詢參數(shù)
        Map<String, Object> queryParam = uniHttpRequest.getHttpUrl().getQueryParam();
        Map<String, Object> paramsMap = this.reorderingQueryParamMap(snMapParams, queryParam);
        System.out.println("處理之后的請(qǐng)求參數(shù):" + paramsMap);
        //第一種請(qǐng)求參數(shù)重排序
        uniHttpRequest.getHttpUrl().setQueryParam(paramsMap);
    }
    return uniHttpRequest;
}

經(jīng)過這樣的改造和設(shè)計(jì),我們就完美的解決了在UniHttp中請(qǐng)求參數(shù)順序不可控的問題。需要注意的是,參數(shù)的加密順序和請(qǐng)求順序一致即可。成功請(qǐng)求界面如下:

5、三種方法的使用場景及對(duì)比

以上這三種方法都能滿足在UniHttp中實(shí)現(xiàn)請(qǐng)求參數(shù)動(dòng)態(tài)調(diào)整的需求,我們將從代碼通用性和改造復(fù)雜度來進(jìn)行對(duì)比:

序號(hào)處理方式通用性改造復(fù)雜度缺點(diǎn)
1客戶端兼容需要根據(jù)請(qǐng)求參數(shù)定制
2兼容Get調(diào)參只支持Get方法
3重寫QueryParam代碼稍微復(fù)雜一點(diǎn),維護(hù)難度高

以上三種思路都能很好的滿足業(yè)務(wù)需要,但是具體采用哪種方式,還需要大家根據(jù)自己的場景進(jìn)行選擇。沒有最好的架構(gòu),只有更好的架構(gòu),架構(gòu)是慢慢演化而來,而不是一蹴而就,良好的架構(gòu)值得好好學(xué)習(xí)。

四、總結(jié)

以上就是本文的主要內(nèi)容,為了解決Java調(diào)用UniHttp接口時(shí)請(qǐng)求參數(shù)亂序?qū)е掳俣萐N簽名認(rèn)證失敗的問題。本文將詳細(xì)探討這三種解決策略,并通過具體的代碼示例和實(shí)際操作步驟,幫助開發(fā)者理解和應(yīng)用這些方法。本文的研究意義在于為Java開發(fā)者提供一種系統(tǒng)性的解決方案,幫助他們解決在接口調(diào)用過程中遇到的請(qǐng)求參數(shù)亂序問題。通過深入分析問題的根源,并提出有效的解決策略,本文旨在提高接口調(diào)用的成功率,減少開發(fā)過程中的錯(cuò)誤和風(fēng)險(xiǎn)。同時(shí),本文的研究成果也可以為其他使用類似接口調(diào)用框架和簽名認(rèn)證機(jī)制的開發(fā)者提供參考和借鑒。博文由淺入深,按照問題重現(xiàn)、查找原因、問題突破的方式對(duì)相關(guān)內(nèi)容進(jìn)行講解,希望大家都能掌握著三種不同的處理方式。

以上就是Java調(diào)用UniHttp接口請(qǐng)求失敗的三種解決策略的詳細(xì)內(nèi)容,更多關(guān)于Java調(diào)用接口請(qǐng)求的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java線程池內(nèi)部任務(wù)出異常后如何知道是哪個(gè)線程出了異常

    Java線程池內(nèi)部任務(wù)出異常后如何知道是哪個(gè)線程出了異常

    在Java線程池中當(dāng)任務(wù)執(zhí)行過程中發(fā)生異常時(shí),識(shí)別發(fā)生異常的任務(wù)所對(duì)應(yīng)的線程是一個(gè)常見的調(diào)試需求,這篇文章主要介紹了Java線程池內(nèi)部任務(wù)出異常后如何知道是哪個(gè)線程出了異常的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • Java深入分析動(dòng)態(tài)代理

    Java深入分析動(dòng)態(tài)代理

    動(dòng)態(tài)代理指的是,代理類和目標(biāo)類的關(guān)系在程序運(yùn)行的時(shí)候確定的,客戶通過代理類來調(diào)用目標(biāo)對(duì)象的方法,是在程序運(yùn)行時(shí)根據(jù)需要?jiǎng)討B(tài)的創(chuàng)建目標(biāo)類的代理對(duì)象。本文將通過案例詳細(xì)講解一下Java動(dòng)態(tài)代理的原理及實(shí)現(xiàn),需要的可以參考一下
    2022-07-07
  • Java詳細(xì)講解Math和Random類中有哪些常用方法

    Java詳細(xì)講解Math和Random類中有哪些常用方法

    Math類位于java.lang包中,包含很多用于科學(xué)計(jì)算的類方法,這些方法可以直接通過類名調(diào)用。Random類獲取隨機(jī)數(shù),位于java.util包中,本篇帶你了解它們的常用方法
    2022-05-05
  • Java窗口精細(xì)全方位講解

    Java窗口精細(xì)全方位講解

    這篇文章呢,將會(huì)系統(tǒng)的精細(xì)的教會(huì)鐵鐵們?nèi)绾巫约簩懸粋€(gè)完整的窗口;看完之后窗口穩(wěn)拿下!!!所以呢由于詳細(xì),知識(shí)點(diǎn)多,可能有點(diǎn)長,鐵鐵們慢慢仔細(xì)閱讀吧;文章寫的還是一如既往快樂的,哈哈哈
    2021-08-08
  • RocketMQ?Broker消息如何刷盤源碼解析

    RocketMQ?Broker消息如何刷盤源碼解析

    這篇文章主要為大家介紹了RocketMQ?Broker消息如何刷盤源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • 登錄EasyConnect后無法通過jdbc訪問服務(wù)器數(shù)據(jù)庫問題的解決方法

    登錄EasyConnect后無法通過jdbc訪問服務(wù)器數(shù)據(jù)庫問題的解決方法

    描述一下近期使用EasyConnect遇到的問題,下面這篇文章主要給大家介紹了關(guān)于登錄EasyConnect后無法通過jdbc訪問服務(wù)器數(shù)據(jù)庫問題的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • java對(duì)象與json對(duì)象之間互相轉(zhuǎn)換實(shí)現(xiàn)方法示例

    java對(duì)象與json對(duì)象之間互相轉(zhuǎn)換實(shí)現(xiàn)方法示例

    這篇文章主要介紹了java對(duì)象與json對(duì)象之間互相轉(zhuǎn)換實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了java對(duì)象與json對(duì)象相互轉(zhuǎn)換實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • 一文詳解JDK、Maven、Spring?Boot各版本兼容性問題

    一文詳解JDK、Maven、Spring?Boot各版本兼容性問題

    Spring Boot 作為一個(gè)高度集成的框架,其版本兼容性涉及到多個(gè)方面,這篇文章主要介紹了JDK、Maven、Spring?Boot各版本兼容性問題的相關(guān)資料,需要的朋友可以參考下
    2026-01-01
  • java編程之xpath介紹

    java編程之xpath介紹

    這篇文章主要介紹了java編程之xpath介紹,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • 一文精通Java 多線程之全方位解讀

    一文精通Java 多線程之全方位解讀

    Java 給多線程編程提供了內(nèi)置的支持。 一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù),多線程是多任務(wù)的一種特別的形式,但多線程使用了更小的資源開銷
    2021-10-10

最新評(píng)論

平果县| 万年县| 娄烦县| 秦安县| 钦州市| 绥化市| 阳春市| 宝鸡市| 昌邑市| 花垣县| 库车县| 阜康市| 金华市| 罗平县| 天柱县| 六盘水市| 苍梧县| 珲春市| 万州区| 九台市| 新巴尔虎右旗| 高平市| 涟水县| 灵台县| 锦州市| 延安市| 新营市| 泽普县| 汉川市| 安达市| 新邵县| 永嘉县| 宕昌县| 宣汉县| 四平市| 阿图什市| 根河市| 汉阴县| 梨树县| 鄂伦春自治旗| 瑞金市|