首頁 > 軟體

Java9新特性對HTTP2協定支援與非阻塞HTTP API

2022-03-15 19:00:19

在HTTP/1.1 釋出了16 年之後,IETF在2015年終於通過了HTTP/2 協定。HTTP/2協定旨在降低延遲,滿足當今時代對於資訊響應時間的要求。在這篇文章中,我會簡要的對HTTP/2協定進行介紹,然後我們將重點放在研究Java9中對HTTP/2支援及其HTTP使用者端API的變化。

我計劃在後續的一段時間內,寫一系列關於java 9的文章,雖然java 9 不像Java 8或者Java 11那樣的核心java版本,但是還是有很多的特性值得關注。期待您能關注我,我將把java 9 寫成一系列的文章,大概十篇左右,本文是第9篇。

java9在interface中定義私有方法詳解

java9版本特性資源自動關閉的語法增強

Java9版本新特性同一個Jar支援多JDK版本執行

java9新特性Reactive Stream響應式程式設計 API

java9新特性Collection集合類的增強與優化方法範例

Java9新特性Stream流API優化與增強

Java9新特性Java.util.Optional優化與增強解析

Java9新特性Module模組化程式設計範例演繹

一、HTTP/2簡介

HTTP/2 旨在減輕 HTTP/1.1 維護複雜基礎結構所造成的痛苦,效能良好。儘管 HTTP/2 仍然與 HTTP/1.1 向後相容,但它不再是基於文字的協定。

HTTP/2 多路複用使單個連線可以處理多個雙向流,允許使用者端通過單個連線同時下載多個資源。

HTTP 1.x 協定是基於文字的,因此報文很冗長。有的時候,同一組 HTTP Headers被一遍又一遍地交換。HTTP/2 通過跨請求維護 HTTP Headers,消除重複交換的資料,大大減少了資料互動所需的頻寬。

HTTP/2資料推播

您可能認為HTTP/2的伺服器端資料推播是對 WebSockets 的某種延續或升級,但情況並非如此。雖然 WebSockets 是使用者端和伺服器之間全雙工通訊的一種方法,以便伺服器在建立 TCP 連線後將資料傳送到使用者端,但 HTTP/2 提供了一種不同的解決方案。

HTTP/2 推播是主動向使用者端傳送資源,而無需從使用者端的角度發起資源請求。這意味著伺服器端根據一個請求可能知道網站進一步需要的其他資源,並且早在使用者端再次發起請求它們之前,就可以一併(提前)傳送所有資源。

目前支援 HTTP/2 的 Java HTTP 使用者端

  • Jetty
  • Netty
  • OkHttp
  • Vert.x
  • Firefly

但是在這篇文章中,我們不會介紹這些Java 使用者端軟體,而是介紹Java9提供的HTTP/2支援。

二、Java 9 的 HTTP/2 使用者端

首先使用Java 9的語法進行模組的匯入 。jdk.incubator.httpclient

module com.springui.echo.client {
    requires jdk.incubator.httpclient;
}

Java 9 新的 HTTP Cient API 遵循構建器模式。HttpClient是用來操作HTTP請求的入口點,先構建後使用。

HttpClient client = HttpClient
    .newBuilder()
    .version(Version.HTTP_2)  //支援HTTP2
    .build();

在阻塞模式下傳送請求

一旦我們有了一個 HttpClient範例,就可以用它來傳送HttpRequest,HttpRequest範例也可以使用構造器建立。

HttpResponse<String> response = client.send(
    HttpRequest
        .newBuilder(TEST_URI)  //請求地址
        .POST(BodyProcessor.fromString("Hello world")) //POST報文資料
        .build(),
    BodyHandler.asString()  //請求響應資料處理,接收字串
);

請求發出去之後,執行緒會一直阻塞直到得到響應資料,這個和JAVA 8及之前的HTTP API是一樣的。但是Java 9提供了以非同步非阻塞傳送處理請求的方法,更適合高並行的HTTP請求與處理。

以非阻塞模式傳送請求(Java 9)

在下面的範例中,10 個隨機整數以非同步方式傳送請求。

List<CompletableFuture<String>> responseFutures = 
        IntStream.of(1,2,3,4,5,6,7,8,9,10)  //10個整數形成IntStream,Java 8的語法
        .mapToObj(String::valueOf) //10個整數轉換成字串,Java 8的語法
        .map(message -> client.sendAsync( //將10個整數位符串作為內容,傳送10個非同步請求
                HttpRequest.newBuilder(TEST_URI)
                        .POST(HttpRequest.BodyProcessor.fromString(message))
                        .build(),
                HttpResponse.BodyHandler.asString()
             ).thenApply(HttpResponse::body)  //以CompletableFuture<HttpResponse.body()>作為流處理的返回值
        )
        .collect(Collectors.toList());  //將Stream轉成List

上面的例子大量的使用了Java 8的Stream流式處理的API,如果不熟悉的同學,可以翻看我以前寫的一些文章。

sendAsync方法的返回值CompletableFuture<HttpResponse<String>>,使用thenApply(HttpResponse::body) 作了進一步的處理,最終返回值是CompletableFuture<String>。

CompletableFuture是Java非同步程式設計的知識,將並行的非同步處理結果列印出來。

responseFutures.stream().forEach(future -> {
    LOGGER.info("Async response: " + future.getNow(null));
});

你會注意到,最終的列印紀錄檔可能不是按照順序1、2、3、4、5、6、7、8、9、10進行處理的,因為所有的請求都是非同步傳送出去的,返回的結果是CompletableFuture用於非同步處理的結果。

三、支援HTTP2的Push-Promise Frames

以上所有範例在 HTTP/1.1協定下都可以完成,只是新加了非阻塞的非同步API,也沒涉及到 HTTP/2 特性啊。別急,Java 9 Client API與HTTP/2結合最緊密的就是:可以使用HTTP2傳送一個請求,得到多個非同步資料結果。(某些資料提前推播,當然這需要伺服器端也支援HTTP/2進行配合)

Map<HttpRequest,CompletableFuture<HttpResponse<String>>> responses =
        client.sendAsync(    //注意這裡只傳送一次請求
          HttpRequest.newBuilder(TEST_URI)
                  .POST(HttpRequest.BodyProcessor.fromString(TEST_MESSAGE))
                  .build(),
          HttpResponse.MultiProcessor.asMap(    //多個資源的響應結果
                  request -> Optional.of(HttpResponse.BodyHandler.asString())
          )
).join();
responses.forEach((request, responseFuture) -> {
  LOGGER.info("Async response: " + responseFuture.getNow(null));
});

從Java 9的角度來看,新的HTTP/2使用者端API看起來不錯。但筆者覺得目前相關技術的使用還不是很成熟,我覺得大家暫時嚐嚐鮮就可以。

以上就是Java9新特性對HTTP2協定的支援與非阻塞HTTP API的詳細內容,更多關於支援HTTP2協定及非阻塞HTTP API的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com