天天看點

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

大家好,我是二哥呀!

今天來給大家推薦一款直擊痛點的 HTTP 用戶端架構,可以超高效率地完成和第三方接口的對接。

在介紹本篇的主角之前,我們先來了解下 Java 生态中的 HTTP 元件庫,大緻可以分為三類:

JDK 自帶的 HttpURLConnection 标準庫;

Apache HttpComponents HttpClient;

OkHttp。

使用 HttpURLConnection 發起 HTTP 請求最大的優點是不需要引入額外的依賴,但是使用起來非常繁瑣,也缺乏連接配接池管理、域名機械控制等特性支援。

使用标準庫的最大好處就是不需要引入額外的依賴,但使用起來比較繁瑣,就像直接使用 JDBC 連接配接資料庫那樣,需要很多模闆代碼。來發起一個簡單的 HTTP POST 請求吧。

public class HttpUrlConnectionDemo {
    public static void main(String[] args) throws IOException {
        String urlString = "https://httpbin.org/post";
        String bodyString = "password=123";
        URL url = new URL(urlString);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        OutputStream os = conn.getOutputStream();
        os.write(bodyString.getBytes("utf-8"));
        os.flush();
        os.close();
        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            InputStream is = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            System.out.println("響應内容:" + sb.toString());
        } else {
            System.out.println("響應碼:" + conn.getResponseCode());
        }
    }
}      

HttpURLConnection 發起的 HTTP 請求比較原始,基本上算是對網絡傳輸層的一次淺層次的封裝;有了 HttpURLConnection 對象後,就可以擷取到輸出流,然後把要發送的内容發送出去;再通過輸入流讀取到伺服器端響應的内容;最後列印。

不過 HttpURLConnection 不支援 HTTP/2.0,為了解決這個問題,Java 9 的時候官方的标準庫增加了一個更進階别的 HttpClient,再發起 POST 請求就顯得高大上多了,不僅支援異步,還支援順滑的鍊式調用。

public class HttpClientDemo {
    public static void main(String[] args) throws URISyntaxException {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(new URI("https://postman-echo.com/post"))
                .headers("Content-Type", "text/plain;charset=UTF-8")
                .POST(HttpRequest.BodyPublishers.ofString("二哥牛逼"))
                .build();
        client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenAccept(System.out::println)
                .join();
    }
}      

Apache HttpComponents HttpClient 支援的特性也非常豐富:

基于标準、純淨的Java語言,實作了HTTP1.0和HTTP1.1;

以可擴充的面向對象的結構實作了HTTP全部的方法;

支援加密的HTTPS協定(HTTP通過SSL協定);

Request的輸出流可以避免流中内容體直接從socket緩沖到伺服器;

Response的輸入流可以有效的從socket伺服器直接讀取相應内容。

public class HttpComponentsDemo {
    public static void main(String[] args) throws IOException, IOException, ParseException {
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost("http://httpbin.org/post");
            List<NameValuePair> nvps = new ArrayList<>();
            nvps.add(new BasicNameValuePair("name", "二哥"));
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, Charset.forName("UTF-8")));
            try (CloseableHttpResponse response2 = httpclient.execute(httpPost)) {
                System.out.println(response2.getCode() + " " + EntityUtils.toString(response2.getEntity()));
            }
        }
    }
}      

OkHttp 是一個執行效率比較高的 HTTP 用戶端:

支援 HTTP/2.0,當多個請求對應同一個 Host 位址時,可共用同一個 Socket;

連接配接池可減少請求延遲;

支援 GZIP 壓縮,減少網絡傳輸的資料大小;

支援 Response 資料緩存,避免重複網絡請求;

public class OkHttpPostDemo {
    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
    OkHttpClient client = new OkHttpClient();
    String post(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(json, JSON);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
    public static void main(String[] args) throws IOException {
        OkHttpPostDemo example = new OkHttpPostDemo();
        String json = "{'name':'二哥'}";
        String response = example.post("https://httpbin.org/post", json);
        System.out.println(response);
    }
}      

那今天介紹的這款輕量級的 HTTP 用戶端架構 Forest,正是基于 Httpclient和OkHttp 的,屏蔽了不同細節的 HTTP 元件庫所帶來的所有差異。

Forest 的字面意思是森林的意思,更内涵點的話,可以拆成For和Rest兩個單詞,也就是“為了Rest”(Rest為一種基于HTTP的架構風格)。 而合起來就是森林,森林由很多樹木花草組成(可以了解為各種不同的服務),它們表面上看獨立,實則在地下根莖交錯縱橫、互相連接配接依存,這樣看就有點現代分布式服務化的味道了。 最後,這兩個單詞反過來讀就像是Resultful。

項目位址:

https://gitee.com/dromara/forest

雖然 star 數還不是很多,但 star 趨勢圖正在趨于爬坡階段,大家可以拿來作為一個練手項目,我覺得還是不錯的選擇。

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

Forest 本身是處理前端過程的架構,是對後端 HTTP API 架構的進一步封裝。

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