天天看點

Duang!Duang!Duang!直擊痛點的一款 HTTP 用戶端架構(Java),牆裂推薦!(2)

前端部分:

通過RPC方式去發送HTTP請求, 友善解耦

支援GET, HEAD, POST等所有請求方法

支援Spring和Springboot內建

JSON字元串到Java對象的自動化解析

XML文本到Java對象的自動化解析

支援靈活的模闆表達式

支援攔截器處理請求的各個生命周期

支援自定義注解

後端部分:

支援OkHttp

支援Httpclient

Forest 容易上手,不需要調用HTTP底層接口,而是像 Dubbo 那樣的 RPC 架構一樣,隻需要定義接口、調用接口即可。幾分鐘内就可完成請求的定義、發送、接收響應、資料解析、錯誤處理、日志列印等過程。

配置輕量,遵循約定優于配置的原則,隻需在需要的時候進行配置,不配置也不會影響Forest請求的正常調用。

簡單優雅,将 HTTP 請求細節封裝成 Java 接口 + 注解的形式,不必再關心發送 HTTP 請求的具體過程。使得 HTTP 請求資訊與業務代碼解耦,友善管理大量 HTTP 的 URL、Header、Body 等資訊。

擴充靈活,允許自定義攔截器、甚至是自定義注解,以此來擴充Forest的能力。

Forest 不需要我們編寫具體的 HTTP 調用過程,隻需要定義一個接口,然後通過 Forest 注解将 HTTP 請求的資訊添加到接口的方法上即可。請求發送方通過調用定義的接口就能自動發送請求和接受請求的響應。

Forest 之是以能做到這樣,是因為它将定義好的接口通過動态代理的方式生成了一個具體的實作類,然後組織、驗證 HTTP 請求資訊,綁定動态資料,轉換資料形式,SSL 驗證簽名,調用後端 HTTP API執行實際請求,等待響應,失敗重試,轉換響應資料到 Java 類型等髒活累活都由這動态代理的實作類給包了。

廢話就不再多說,直接開始實戰。

第一步,添加 Maven 依賴。

<dependency>

   <groupId>com.dtflys.forest</groupId>

   <artifactId>forest-core</artifactId>

   <version>1.5.1</version>

</dependency>

第二步,建構 HTTP 請求。

在 Forest 中,所有的 HTTP 請求資訊都要綁定到某一個接口的方法上,不需要編寫具體的代碼去發送請求。請求發送方通過調用事先定義好 HTTP 請求資訊的接口方法。

public interface ForRestClient {

   @Request(

           url = "http://httpbin.org/post",

           type = "POST"

   )

   String simplePost(@Body("name") String name);

}

通過 @Post 注解,将上面的ForRestClient接口中的 simplePost() 方法綁定了一個 HTTP 請求,使用 POST 方式,可以使用@Body注解修飾參數的方式,将傳入參數的資料綁定到 HTTP 請求體中。然後将請求響應的資料以String的方式傳回給調用者。

第三步,調用接口。

public class ForRestDemo {
    public static void main(String[] args) {
        // 執行個體化Forest配置對象
        ForestConfiguration configuration = ForestConfiguration.configuration();
        configuration.setBackendName("httpclient");
        // 通過Forest配置對象執行個體化Forest請求接口
        ForRestClient myClient = configuration.createInstance(ForRestClient.class);
        // 調用Forest請求接口,并擷取響應傳回結果
        String result = myClient.simplePost("二哥");
        System.out.println(result);
    }
}      

ForestConfiguration為 Forest 的全局配置對象類,所有的 Forest 的全局基本配置資訊由此類進行管理。

可以來看一下運作後的日志資訊:

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "name": "\u4e8c\u54e5"
  }, 
  "headers": {
    "Content-Length": "23", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Apache-HttpClient/4.5.2 (Java/11.0.8)", 
    "X-Amzn-Trace-Id": "Root=1-60b533aa-58b41e4967803d99593c53a0"
  }, 
  "json": null, 
  "origin": "161.81.21.32", 
  "url": "http://httpbin.org/post"
}      

此時,一個簡單的 Forest 上手小栗子就跑通了。

如果是 Spring Boot 項目的話,就不需要 ForestConfiguration 了,隻需要在啟動類或者配置類上添加 @ForestScan 注解就可以了。

@SpringBootApplication
@Configuration
@ForestScan(basePackages = "com.yoursite.client")
public class MyApp {
 ...
}      

Forest 除了支援GET和POST,也支援其他幾種 HTTP 請求方式,比如PUT、HEAD、 OPTIONS、DELETE。隻需要在建構接口的時候使用對應的注解就可以了,比如說 PUT:

// PUT請求

@Put("http://localhost:8080/hello")

String simplePut();

在POST和PUT請求方法中,通常使用 HTTP 請求體進行資料傳輸,在 Forest 中,可以使用 @Body、@JSONBody、@XMLBody 等多種方式設定請求體資料。

/**

* 直接修飾一個JSON字元串

*/

@Post("http://localhost:8080/hello/user")

String helloUser(@JSONBody String userJson);

Forest 請求會自動将響應的傳回資料反序列化成對應的資料類型,分兩步走。

第一步:定義dataType屬性

dataType屬性指定了該請求響應傳回的資料類型,可選的資料類型有三種: text, json, xml,預設為 text。

/**
 * dataType為json或xml時,Forest會進行相應的反序列化
 */
@Request(
    url = "http://localhost:8080/text/data",
    dataType = "json"
)
Map getData();      

第二步:指定反序列化的目标類型

反序列化需要一個目标類型,而該類型其實就是方法的傳回值類型,如傳回值為String就會反序列成String字元串,傳回值為Map就會反序列化成一個HashMap對象,也可以指定為自定義的Class類型。

如果有這樣一個 User 類:

public class User {
    private String username;
    private String score;
   
    // Setter和Getter ...
}      

傳回的資料為 JSON 字元串:

{"username":  "Foo", "score":  "82"}

1

那請求接口就應該定義成這樣:

* dataType屬性指明了傳回的資料類型為JSON

@Get(

   url = "http://localhost:8080/user?id=${0}",

   dataType = "json"

)

User getUser(Integer id)

另外,大家需要了解一下 Gzip,它是現在一種流行的檔案壓縮算法,有相當廣泛的應用範圍。尤其是當Gzip用來壓縮存文本檔案的時候效果尤為明顯,大概能減少70%以上的檔案大小。很多 HTTP 伺服器都支援 Gzip,比如 Tomcat,經過這些服務壓縮過的資料可以降低網絡傳輸的流量,提高用戶端的響應速度。

Forest從1.5.2-BETA版本開始支援Gzip的解壓,其解壓的方式也很簡單,在方法或接口類上加上 @DecompressGzip 注解即可。

* 為請求方法添加Gzip解壓能力

@Get("/transaction")

@DecompressGzip

String transaction(String infno);

更重要的一點是,Forest 可以通過設定@Request注解的async屬性為true來實作異步請求。

@Request(
        url = "http://localhost:8080/hello/user?username=${0}",
        async = true,
        headers = {"Accept:text/plain"}
)
void asyncGet(String username, OnSuccess<String> onSuccess);      

異步請求時,通過 OnSuccess<T> 回調函數來接受響應資料,而不是通過接口方法的傳回值,是以這裡的傳回值類型一般會定義為void。

調用該接口方法時,可以通過下面的方式:

myClient.send("foo", (String resText, ForestRequest request, ForestResponse response) -> {
        // 成功響應回調
        System.out.println(resText);    
    },
    (ForestRuntimeException ex, ForestRequest request, ForestResponse response) -> {
        // 異常回調
        System.out.println(ex.getMessage());
    });      

除了上面提到的這些功能,Forset 還支援更進階的用法:

HTTPS

檔案上傳下載下傳

攔截器

使用代理

自定義注解

大家可以去看一下 Forset 的官方文檔,然後在本地實踐一下,還是能學到不少知識的,尤其是 HTTPS 和檔案上傳下載下傳這塊,隻需要簡單的配置就能完成,我個人感覺還是挺值得去學習和借鑒的。

開源精神難能可貴,好的開源需要大家的添磚加瓦和支援。希望這篇文章能給大家在選擇 HTTP 用戶端架構時帶來一個新的選擇,對,就是 Forest。

這篇文章不僅介紹了 Forest 這個輕量級的 HTTP 用戶端架構,還回顧了它的底層實作:HttpClient 和 OkHttp,希望能對大家有所幫助。

GitHub 上星标 115k+ 的 Java 教程

作為 CSDN 上 Java 領域的優質創作者(擁有 27 萬粉的男人),二哥一直在想,怎麼幫助大家更好地學習 Java,于是我連載了通俗易懂的《教妹學Java》,目前已更新了 36 篇。

與此同時,為了幫助大家更好的入門 Java,我花了一周的時間整理了一份 GitHub 上星标 115k+ 的 Java 教程。

裡面涵蓋了 Java 所有的知識點,包括 Java 文法、Java 集合架構、Java IO、Java 并發程式設計和 Java 虛拟機,内容不多,隻講重點。很多讀者看完後都來私信我,說這本 PDF 的品質真高:GitHub 上星标 115k+ 的 Java 教程下載下傳位址(點選)

另附:純 Java 版的 LeetCode 刷題筆記,對算法薄弱和需要提高算法的同學很有幫助。

最後,希望大家都能在 Java 這條路上越走越遠,拿到更好的 offer,走上逆襲之路。

我是二哥呀,我們下期見~