首頁  >  文章  >  Java  >  Java 9的HTTP2協定支援與非阻塞HTTP API分析

Java 9的HTTP2協定支援與非阻塞HTTP API分析

王林
王林轉載
2023-04-22 21:52:061020瀏覽

一、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方法的回傳值CompletableFuture721c5bd4f0360fdcda122bb99928a389>,使用thenApply(HttpResponse::body) 作了進一步的處理,最終回傳值是CompletableFuturef7e83be87db5cd2d9a8a0b8117b38cd4。

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看起來不錯。但筆者覺得目前相關技術的使用還不是很成熟,我覺得大家暫時嚐嚐就可以。

以上是Java 9的HTTP2協定支援與非阻塞HTTP API分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除