1.背景
因為業務關系,要和許多不同第三方公司進行對接,這些服務商都提供基于http的api,但是每家公司提供api具體細節差別很大,有的基于RESTFUL規范,有的基于傳統的http規范;有的需要在header里放置簽名,有的需要SSL的雙向認證,有的只需要SSL的單向認證;有的以JSON 方式進行序列化,有的以XML方式進行序列化,類似于這樣細節的差別太多了,
不同的公司API規范不一樣,這很正常,但是對于我來說,我如果想要代碼變得優雅,我就必須解決一個痛點:
不同服務商API那么多的差異點,如何才能維護一套不涉及業務的公共http呼叫套件,最好通過配置或者簡單的引數就能區分開來,進行方便的呼叫?
我當然知道有很多優秀的大名鼎鼎的http開源框架可以實作任何形式的http呼叫,在多年的開發經驗中我都有使用過,比如apache的httpClient包,非常優秀的Okhttp,jersey client,
這些http開源框架的介面使用相對來說,都不太一樣,不管選哪個,在我這個場景里來說,我都不希望在呼叫每個第三方的http api時寫上一堆http呼叫代碼,
所以,在這個場景里,我得對每種不同的http api進行封裝,這樣的代碼才能更加優雅,業務代碼和http呼叫邏輯耦合度更低,
可惜,我比較懶,一來覺得封裝起來比較費時間,二來覺對封裝這種底層http呼叫來說,應該有更好的選擇,不想自己再去造輪子,
于是,我發現了一款優秀的開源http框架,能屏蔽不同細節http api所帶來的所有差異,能通過簡單的配置像呼叫rpc框架一樣的去完成極為復雜的http呼叫,
Forest
https://gitee.com/dt_flys/forest

2.上手
Forest支持了Springboot的自動裝配,所以只需要引入一個依賴就行
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>spring-boot-starter-forest</artifactId>
<version>1.3.0</version>
</dependency>
定義自己的介面類
public interface MyClient {
@Request(url = "http://baidu.com")
String simpleRequest();
@Request(
url = "http://ditu.amap.com/service/regeo",
dataType = "json"
)
Map getLocation(@DataParam("longitude") String longitude, @DataParam("latitude") String latitude);
}
在啟動類里配置代理介面類的掃描包
@SpringBootApplication
@ForestScan(basePackages = "com.example.demo.forest")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
這時候,你就可以從spring容器中注入你的代理介面,像呼叫本地方法一樣去呼叫http的api了
@Autowired
private MyClient myClient;
@Override
public void yourMethod throws Exception {
Map result = myClient.getLocation("124.730329","31.463683");
System.out.println(JSON.toJSONString(result,true));
}
日志列印,Forest列印了內部所用的http框架,和實際請求url和回傳,當然日志可以通過配置去控制開關,

3.特點
我覺得對于尤其是做對接第三方api的開發同學來說,這款開源框架能幫你提高很多效率,
Forest 底層封裝了2種不同的http框架:Apache httpClient和OKhttp,所以這個開源框架并沒有對底層實作進行重復造輪子,而是在易用性上面下足了功夫,
我用Forest最終完成了和多個服務商api對接的專案,這些風格迥異的API,我僅用了1個小時時間就把他們轉化為了本地方法,然后專案順利上線,
Forest作為一款更加高層的http框架,其實你并不需要寫很多代碼,大多數時候,你僅通過一些配置就能完成http的本地化呼叫,而這個框架所能覆寫的面,卻非常之廣,滿足你絕大多數的http呼叫請求,
Forest有以下特點:
- 以
Httpclient和OkHttp為后端框架 - 通過呼叫本地方法的方式去發送Http請求, 實作了業務邏輯與Http協議之間的解耦
- 相比Feign更輕量,不依賴
Spring Cloud和任何注冊中心 - 支持所有請求方法:
GET,HEAD,OPTIONS,TRACE,POST,DELETE,PUT,PATCH - 支持靈活的模板運算式
- 支持過濾器來過濾傳入的資料
- 基于注解、配置化的方式定義
Http請求 - 支持
Spring和Springboot集成 - 實作
JSON和XML的序列化和反序列化 - 支持JSON轉換框架:
Fastjson,Jackson,Gson - 支持
JAXB形式的XML轉換 - 支持
SSL的單向和雙向加密 - 支持http連接池的設定
- 可以通過
OnSuccess和OnError介面引數實作請求結果的回呼 - 配置簡單,一般只需要
@Request一個注解就能完成絕大多數請求的定義 - 支持異步請求呼叫
4.兩個很棒的功能
這里不對使用方式和配置方式一一描述,有興趣的可以去閱讀詳細檔案:
https://dt_flys.gitee.io/forest
這里只想分析這個框架2個我認為比較好的功能
4.1 模板運算式和引數的映射系結功能
模板運算式在使用的時候特別方便,舉個栗子
@Request(
url = "${0}/send?un=${1}&pw=${2}&ph=${3}&ct=${4}",
type = "get",
dataType = "json"
)
public Map send(
String base,
String userName,
String password,
String phone,
String content
);
上述是用序號下標進行取值,也可以通過名字進行取值:
@Request(
url = "${base}/send?un=${un}&pw=${pw}&ph=${3}&ct=${ct}",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataVariable("un") String userName,
@DataVariable("pw") String password,
@DataVariable("ph") String phone,
@DataVariable("ct") String content
);
甚至于可以這樣簡化寫:
@Request(
url = "${base}/send",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataParam("un") String userName,
@DataParam("pw") String password,
@DataParam("ph") String phone,
@DataParam("ct") String content
);
以上三種寫法是等價的
當然你也可以把引數系結到header和body里去,你甚至于可以用一些運算式簡單的把物件序列化成json或者xml:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
headers = {"Authorization: ${1}"},
data = "https://www.cnblogs.com/bryan31/p/${json($0)}"
)
public PayResponse pay(PayRequest request, String auth);
當然資料系結這塊詳情請參閱檔案
4.2 對HTTPS的支持
以前用其他http框架處理https的時候,總覺得特別麻煩,尤其是雙向證書,每次碰到問題也只能去baidu,然后根據別人的經驗來修改自己的代碼,
Forest對于這方面也想的很周到,底層完美封裝了對https單雙向證書的支持,也是只要通過簡單的配置就能迅速完成,舉個雙向證書栗子:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
keyStore = "pay-keystore",
data = "https://www.cnblogs.com/bryan31/p/${json($0)}"
)
public PayResponse pay(PayRequest request);
其中pay-keystore對應著application.yml里的ssl-key-stores
forest:
...
ssl-key-stores:
- id: pay-keystore
file: test.keystore
keystore-pass: 123456
cert-pass: 123456
protocols: SSLv3
這樣設定,就ok了,剩下的,就是本地代碼形式的呼叫了,
5.最后
Forest有很多其他的功能設定,如果感興趣的同學還請仔細去閱讀檔案和示例,
但是我想說的是,相信看到這里,很多人一定會說,這不就是Feign嗎?
我在開發Spring Cloud專案的時候,也用過一段時間Feign,個人感覺Forest的確在配置和用法上和Feign的設計很像,但Feign的角色更多是作為Spring Cloud生態里的一個成員,充當RPC通信的角色,其承擔的不僅是http通訊,還要對注冊中心下發的呼叫地址進行負載均衡,
而Forest這個開源專案其定位則是一個高階的http工具,主打友好和易用性,從使用角度出發,個人感覺Forest配置性更加簡單直接,提供的很多功能也能解決很多人的痛點,
開源精神難能可貴,好的開源需要大家的添磚加瓦和支持,希望這篇文章能給大家在選擇http客戶端框架時帶來一個新的選擇:Forest
聯系作者
微信關注 「元人部落」:
關注后回復 "資料" 免費獲取50G的技術資料,包含一整套企業級微服務課程以及一套秒殺課程

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/138069.html
標籤:Java
