Spring Cloud Feign實現動態URL
需求描述
動態URL的需求場景:
有一個異步服務S,它為其他業務(業務A,業務B…)提供異步服務接口,在這些異步接口中執行完指定邏輯之後需要回調相應業務方的接口。
這在諸如風控審核,支付回調等場景中挺常見的。
那麼,這個回調業務方接口該怎麼實現呢?
首先,需要約定好回調這些業務方接口時的請求方法(通常為POST請求),請求參數格式(通常為JSON格式,方便擴展)和響應消息格式(通常為JSON格式)。
具體調用業務方接口時有2種辦法來實現:
1.在服務S的每一個異步接口中都獨立寫一套回調的邏輯
2.因為回調的方法類型和參數格式是約定好的,所以可以寫一個統一的公共回調方法即可
方法1顯然不是最優選擇,這樣做會帶來大量重復的代碼邏輯,而且非常不利用後期維護和升級。
方法2的實現更加靈活一些,便於擴展。
如下將闡述如何使用Feign框架定義一個公共的回調方法。
具體實現
在Feign中能實現動態URL的基礎是框架本身就支持,隻需要在接口方法中包含一個java.net.URI參數,Feign就會將該參數值作為目標主機地址,詳見Interface Annotations一節中的“Overriding the Request Line”部分。
如下將分別闡述獨立使用Feign和使用Spring Cloud OpenFeign實現定義統一的回調方法。
使用Feign定義統一回調方法
定義統一回調方法:
public interface CallbackAPI { /** * 統一回調接口方法,請求消息體格式為JSON,響應消息體格式也為JSON * @param host 接口主機地址,如:http://localhost:8080,該參數是實現動態URL的關鍵 * @param path 接口路徑,如:/test/hello * @param queryMap 動態URL參數集合 * @param body 請求消息體對象 * @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); /** * 統一回調接口方法,請求消息體格式為JSON,響應消息體格式也為JSON * @param uri 完整的請求路徑地址,如:http://localhost:8080/test/hello * @param queryMap 動態URL參數集合 * @param body 請求消息體對象 * @return */ @RequestLine("POST") @Headers({ "Content-Type: application/json", "Accept: application/json" }) Object callback(URI uri, @QueryMap Map<String, Object> queryMap, Subject body); }
調用回調方法:
CallbackAPI callbackAPI = Feign.builder() .encoder(new GsonEncoder()) .decoder(new GsonDecoder()) .logger(new Slf4jLogger()) .logLevel(Logger.Level.FULL) .target(CallbackAPI.class, "EMPTY"); // 註意:這裡的url參數不能為空字符串,但是可以設置為任意字符串值,在這裡設置為“EMPTY” String uri = "http://localhost:8080"; Map<String, Object> queryMap = new HashMap<>(0); queryMap.put("k", "v"); Subject body = Subject.builder().id(10).build(); // 請求主機地址與路徑分開傳遞 callbackAPI.callback(URI.create(uri), "/test/simple/post/json", queryMap, body); // 直接將完整請求完整路徑作為uri類型參數 callbackAPI.callback(URI.create("http://localhost:8080/test/simple/post/json"), queryMap, body);
詳細請求日志如下:
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)
顯然,動態設置目標主機和接口路徑已經成功瞭。
使用Spring Cloud Feign定義統一回調方法
在Spring Cloud Feign中實現定義統一回調接口方法可以直接使用註解進行標註,非常簡潔。
定義統一回調方法:
// 註意:這裡的url屬性值不能為空字符串,但是可以設置為任意字符串值,在這裡設置為“EMPTY” @FeignClient(value = "CallbackAPI", url = "EMPTY", configuration = CallbackConfiguration.class) public interface CallbackAPI { /** * 統一回調接口方法,請求消息體格式為JSON,響應消息體格式也為JSON * @param host 接口主機地址,如:http://localhost:8080 * @param path 接口路徑,如:/test/hello * @param queryMap 動態URL參數集合 * @param body 請求消息體對象 * @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); /** * 統一回調接口方法,請求消息體格式為JSON,響應消息體格式也為JSON * @param uri 完整的請求路徑地址,如:http://localhost:8080/test/hello * @param queryMap 動態URL參數集合 * @param body 請求消息體對象 * @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); } // 回調接口配置 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; } }
調用回調方法:
@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(); // 請求主機地址與路徑分開傳遞 this.callbackAPI.callback(URI.create(uri), "/test/simple/post/json", queryMap, subject); // 直接將完整請求完整路徑作為uri類型參數 this.callbackAPI.callback(URI.create("http://localhost:8080/test/simple/post/json"), queryMap, subject);
詳細請求日志如下:
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中同樣實現動態URL的效果。
總結
在Feign中實現動態URL時:
1.可以使用URI類型的參數作為請求目標主機地址或者完整請求地址
2.如果URI類型的參數值僅為主機部分,請求路徑部分可以使用表達式進行替換
【參考】
https://www.cnblogs.com/syui-terra/p/14386188.html Feign 動態URL 解決記錄
https://blog.csdn.net/kysmkj/article/details/89672952 Feign 訪問遠程api,動態指定url
到此這篇關於Spring Cloud Feign實現動態URL的文章就介紹到這瞭,更多相關Spring Cloud Feign 動態URL內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring Cloud Feign實現文件上傳下載的示例代碼
- 使用feign服務調用添加Header參數
- 輕量級聲明式的Http庫——Feign的獨立使用
- feign 打印日志不顯示的問題及解決
- Jersey Restful接口如何獲取參數的問題