Spring Cloud Feign實(shí)現(xiàn)動(dòng)態(tài)URL
需求描述
動(dòng)態(tài)URL的需求場(chǎng)景:
有一個(gè)異步服務(wù)S,它為其他業(yè)務(wù)(業(yè)務(wù)A,業(yè)務(wù)B...)提供異步服務(wù)接口,在這些異步接口中執(zhí)行完指定邏輯之后需要回調(diào)相應(yīng)業(yè)務(wù)方的接口。
這在諸如風(fēng)控審核,支付回調(diào)等場(chǎng)景中挺常見(jiàn)的。
那么,這個(gè)回調(diào)業(yè)務(wù)方接口該怎么實(shí)現(xiàn)呢?
首先,需要約定好回調(diào)這些業(yè)務(wù)方接口時(shí)的請(qǐng)求方法(通常為POST請(qǐng)求),請(qǐng)求參數(shù)格式(通常為JSON格式,方便擴(kuò)展)和響應(yīng)消息格式(通常為JSON格式)。
具體調(diào)用業(yè)務(wù)方接口時(shí)有2種辦法來(lái)實(shí)現(xiàn):
1.在服務(wù)S的每一個(gè)異步接口中都獨(dú)立寫(xiě)一套回調(diào)的邏輯
2.因?yàn)榛卣{(diào)的方法類型和參數(shù)格式是約定好的,所以可以寫(xiě)一個(gè)統(tǒng)一的公共回調(diào)方法即可
方法1顯然不是最優(yōu)選擇,這樣做會(huì)帶來(lái)大量重復(fù)的代碼邏輯,而且非常不利用后期維護(hù)和升級(jí)。
方法2的實(shí)現(xiàn)更加靈活一些,便于擴(kuò)展。
如下將闡述如何使用Feign框架定義一個(gè)公共的回調(diào)方法。
具體實(shí)現(xiàn)
在Feign中能實(shí)現(xiàn)動(dòng)態(tài)URL的基礎(chǔ)是框架本身就支持,只需要在接口方法中包含一個(gè)java.net.URI參數(shù),F(xiàn)eign就會(huì)將該參數(shù)值作為目標(biāo)主機(jī)地址,詳見(jiàn)Interface Annotations一節(jié)中的“Overriding the Request Line”部分。
如下將分別闡述獨(dú)立使用Feign和使用Spring Cloud OpenFeign實(shí)現(xiàn)定義統(tǒng)一的回調(diào)方法。
使用Feign定義統(tǒng)一回調(diào)方法
定義統(tǒng)一回調(diào)方法:
public interface CallbackAPI { ? ? /** ? ? ?* 統(tǒng)一回調(diào)接口方法,請(qǐng)求消息體格式為JSON,響應(yīng)消息體格式也為JSON ? ? ?* @param host 接口主機(jī)地址,如:http://localhost:8080,該參數(shù)是實(shí)現(xiàn)動(dòng)態(tài)URL的關(guān)鍵 ? ? ?* @param path 接口路徑,如:/test/hello ? ? ?* @param queryMap 動(dòng)態(tài)URL參數(shù)集合 ? ? ?* @param body 請(qǐng)求消息體對(duì)象 ? ? ?* @return ? ? ?*/ ? ? @RequestLine("POST {path}") ? ? @Headers({ ? ? ? ? "Content-Type: application/json", ? ? ? ? "Accept: application/json" ? ? }) ? ? Object callback(URI host, @Param("path") String path, @QueryMap Map<String, Object> queryMap, Subject body); ? ?/** ? ? ?* 統(tǒng)一回調(diào)接口方法,請(qǐng)求消息體格式為JSON,響應(yīng)消息體格式也為JSON ? ? ?* @param uri 完整的請(qǐng)求路徑地址,如:http://localhost:8080/test/hello ? ? ?* @param queryMap 動(dòng)態(tài)URL參數(shù)集合 ? ? ?* @param body 請(qǐng)求消息體對(duì)象 ? ? ?* @return ? ? ?*/ ? ? @RequestLine("POST") ? ? @Headers({ ? ? ? ? "Content-Type: application/json", ? ? ? ? "Accept: application/json" ? ? }) ? ? Object callback(URI uri, @QueryMap Map<String, Object> queryMap, Subject body); }
調(diào)用回調(diào)方法:
CallbackAPI callbackAPI = Feign.builder() ? ? ? ? .encoder(new GsonEncoder()) ? ? ? ? .decoder(new GsonDecoder()) ? ? ? ? .logger(new Slf4jLogger()) ? ? ? ? .logLevel(Logger.Level.FULL) ? ? ? ? .target(CallbackAPI.class, "EMPTY"); // 注意:這里的url參數(shù)不能為空字符串,但是可以設(shè)置為任意字符串值,在這里設(shè)置為“EMPTY” String uri = "http://localhost:8080"; Map<String, Object> queryMap = new HashMap<>(0); queryMap.put("k", "v"); Subject body = Subject.builder().id(10).build(); // 請(qǐng)求主機(jī)地址與路徑分開(kāi)傳遞 callbackAPI.callback(URI.create(uri), "/test/simple/post/json", queryMap, body); // 直接將完整請(qǐng)求完整路徑作為uri類型參數(shù) callbackAPI.callback(URI.create("http://localhost:8080/test/simple/post/json"), queryMap, body);
詳細(xì)請(qǐng)求日志如下:
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] ---> POST http://localhost:8080/test/simple/post/json?k=v HTTP/1.1
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] Accept: application/json
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] Content-Length: 14
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] Content-Type: application/json
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback]
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] {
"id": 10
}
2022-02-14 15:32:13,118 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] ---> END HTTP (14-byte body)
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] <--- HTTP/1.1 200 (32ms)
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] connection: keep-alive
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] content-length: 9
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] content-type: application/json
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] date: Mon, 14 Feb 2022 07:32:13 GMT
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] keep-alive: timeout=60
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback]
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] {"id":10}
2022-02-14 15:32:13,153 DEBUG [main] f.Logger [Slf4jLogger.java:72] [CallbackAPI#callback] <--- END HTTP (9-byte body)
顯然,動(dòng)態(tài)設(shè)置目標(biāo)主機(jī)和接口路徑已經(jīng)成功了。
使用Spring Cloud Feign定義統(tǒng)一回調(diào)方法
在Spring Cloud Feign中實(shí)現(xiàn)定義統(tǒng)一回調(diào)接口方法可以直接使用注解進(jìn)行標(biāo)注,非常簡(jiǎn)潔。
定義統(tǒng)一回調(diào)方法:
// 注意:這里的url屬性值不能為空字符串,但是可以設(shè)置為任意字符串值,在這里設(shè)置為“EMPTY” @FeignClient(value = "CallbackAPI", url = "EMPTY", configuration = CallbackConfiguration.class) public interface CallbackAPI { ? ? /** ? ? ?* 統(tǒng)一回調(diào)接口方法,請(qǐng)求消息體格式為JSON,響應(yīng)消息體格式也為JSON ? ? ?* @param host 接口主機(jī)地址,如:http://localhost:8080 ? ? ?* @param path 接口路徑,如:/test/hello ? ? ?* @param queryMap 動(dòng)態(tài)URL參數(shù)集合 ? ? ?* @param body 請(qǐng)求消息體對(duì)象 ? ? ?* @return ? ? ?*/ ? ? @RequestMapping(value = "{path}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) ? ? Object callback(URI host, ? ? ? ? ? ? ? ? ? ? @PathVariable("path") String path, ? ? ? ? ? ? ? ? ? ? @SpringQueryMap Map<String, Object> queryMap, ? ? ? ? ? ? ? ? ? ? @RequestBody Object body); ? ? /** ? ? ?* 統(tǒng)一回調(diào)接口方法,請(qǐng)求消息體格式為JSON,響應(yīng)消息體格式也為JSON ? ? ?* @param uri 完整的請(qǐng)求路徑地址,如:http://localhost:8080/test/hello ? ? ?* @param queryMap 動(dòng)態(tài)URL參數(shù)集合 ? ? ?* @param body 請(qǐng)求消息體對(duì)象 ? ? ?* @return ? ? ?*/ ? ? @RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) ? ? Object callback(URI uri, ? ? ? ? ? ? ? ? ? ? @SpringQueryMap Map<String, Object> queryMap, ? ? ? ? ? ? ? ? ? ? @RequestBody Object body); } // 回調(diào)接口配置 public class CallbackConfiguration { ? ? @Bean ? ? public Encoder feignEncoder() { ? ? ? ? return new GsonEncoder(); ? ? } ? ? @Bean ? ? public Decoder feignDecoder() { ? ? ? ? return new GsonDecoder(); ? ? } ? ? @Bean ? ? public Retryer feignRetryer() { ? ? ? ? return new Retryer.Default(); ? ? } ? ? @Bean ? ? public Logger feignLogger() { ? ? ? ? return new Slf4jLogger(); ? ? } ? ? @Bean ? ? public Logger.Level feignLoggerLevel() { ? ? ? ? return Logger.Level.FULL; ? ? } }
調(diào)用回調(diào)方法:
@Autowired CallbackAPI callbackAPI; String uri = "http://localhost:8080"; Map<String, Object> queryMap = new HashMap<>(0); queryMap.put("k", "v"); Subject subject = Subject.builder().id(10).build(); // 請(qǐng)求主機(jī)地址與路徑分開(kāi)傳遞 this.callbackAPI.callback(URI.create(uri), "/test/simple/post/json", queryMap, subject); // 直接將完整請(qǐng)求完整路徑作為uri類型參數(shù) this.callbackAPI.callback(URI.create("http://localhost:8080/test/simple/post/json"), queryMap, subject);
詳細(xì)請(qǐng)求日志如下:
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] ---> POST http://localhost:8080/test/simple/post/json?k=v HTTP/1.1
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] Accept: application/json
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] Content-Length: 14
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] Content-Type: application/json
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback]
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] {
"id": 10
}
2022-02-14 15:38:38.908 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] ---> END HTTP (14-byte body)
2022-02-14 15:38:38.924 DEBUG 20184 --- [ main] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader@539c48307 pairs: {POST /test/simple/post/json?k=v HTTP/1.1: null}{Accept: application/json}{Content-Type: application/json}{User-Agent: Java/1.8.0_271}{Host: localhost:8080}{Connection: keep-alive}{Content-Length: 14}
2022-02-14 15:38:38.945 DEBUG 20184 --- [ main] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader@681e913c6 pairs: {null: HTTP/1.1 200}{Content-Type: application/json}{Content-Length: 9}{Date: Mon, 14 Feb 2022 07:38:38 GMT}{Keep-Alive: timeout=60}{Connection: keep-alive}
2022-02-14 15:38:38.952 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] <--- HTTP/1.1 200 (37ms)
2022-02-14 15:38:38.952 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] connection: keep-alive
2022-02-14 15:38:38.952 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] content-length: 9
2022-02-14 15:38:38.952 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] content-type: application/json
2022-02-14 15:38:38.952 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] date: Mon, 14 Feb 2022 07:38:38 GMT
2022-02-14 15:38:38.953 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] keep-alive: timeout=60
2022-02-14 15:38:38.953 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback]
2022-02-14 15:38:38.955 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] {"id":10}
2022-02-14 15:38:38.955 DEBUG 20184 --- [ main] feign.Logger : [CallbackAPI#callback] <--- END HTTP (9-byte body)
從日志詳情看,在Spring Cloud Feign中同樣實(shí)現(xiàn)動(dòng)態(tài)URL的效果。
總結(jié)
在Feign中實(shí)現(xiàn)動(dòng)態(tài)URL時(shí):
1.可以使用URI類型的參數(shù)作為請(qǐng)求目標(biāo)主機(jī)地址或者完整請(qǐng)求地址
2.如果URI類型的參數(shù)值僅為主機(jī)部分,請(qǐng)求路徑部分可以使用表達(dá)式進(jìn)行替換
【參考】
https://www.cnblogs.com/syui-terra/p/14386188.html Feign 動(dòng)態(tài)URL 解決記錄
https://blog.csdn.net/kysmkj/article/details/89672952 Feign 訪問(wèn)遠(yuǎn)程api,動(dòng)態(tài)指定url
到此這篇關(guān)于Spring Cloud Feign實(shí)現(xiàn)動(dòng)態(tài)URL的文章就介紹到這了,更多相關(guān)Spring Cloud Feign 動(dòng)態(tài)URL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Cloud中關(guān)于Feign的常見(jiàn)問(wèn)題總結(jié)
- 詳解Spring Cloud Feign 熔斷配置的一些小坑
- 詳解spring cloud Feign使用中遇到的問(wèn)題總結(jié)
- spring cloud feign不支持@RequestBody+ RequestMethod.GET報(bào)錯(cuò)的解決方法
- Spring Cloud使用Feign實(shí)現(xiàn)Form表單提交的示例
- 解決Spring Cloud Feign 請(qǐng)求時(shí)附帶請(qǐng)求頭的問(wèn)題
- spring cloud 之 Feign 使用HTTP請(qǐng)求遠(yuǎn)程服務(wù)的實(shí)現(xiàn)方法
相關(guān)文章
Java實(shí)現(xiàn)非阻塞式服務(wù)器的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的非阻塞式服務(wù)器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以參考一下2023-05-05java后端請(qǐng)求過(guò)濾options方式
Optional項(xiàng)是一個(gè)容器對(duì)象,它可以包含非空值,也可以不包含非空值,它用于表示沒(méi)有值,而不是使用?null,引入Optional項(xiàng)是為了幫助開(kāi)發(fā)人員編寫(xiě)更簡(jiǎn)潔、更具表現(xiàn)力的代碼,并避免?NullPointerException2024-01-01SpringBoot與Spring中數(shù)據(jù)緩存Cache超詳細(xì)講解
我們知道內(nèi)存讀取速度遠(yuǎn)大于硬盤(pán)讀取速度,當(dāng)需要重復(fù)獲取相同數(shù)據(jù)時(shí),一次一次的請(qǐng)求數(shù)據(jù)庫(kù)或者遠(yuǎn)程服務(wù),導(dǎo)致在數(shù)據(jù)庫(kù)查詢或者遠(yuǎn)程方法調(diào)用上小號(hào)大量的時(shí)間,最終導(dǎo)致程序性能降低,這就是數(shù)據(jù)緩存要解決的問(wèn)題,學(xué)過(guò)計(jì)算機(jī)組成原理或者操作系統(tǒng)的同學(xué)們應(yīng)該比較熟悉2022-10-10SpringBoot2.0實(shí)現(xiàn)多圖片上傳加回顯
這兩天公司有需求讓做一個(gè)商戶注冊(cè)的后臺(tái)功能,其中需要商戶上傳多張圖片并回顯,本文就使用SpringBoot2.0實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2021-07-07java 數(shù)據(jù)結(jié)構(gòu)基本算法希爾排序
這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)基本算法希爾排序的相關(guān)資料,需要的朋友可以參考下2017-08-08基于SpringBoot多線程@Async的使用體驗(yàn)
這篇文章主要介紹了SpringBoot多線程@Async的使用體驗(yàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12