
在HTTP/1.1 發布了16 年之后,IETF在2015年終于通過了HTTP/2 協議,HTTP/2協議旨在降低延遲,滿足當今時代對于資訊回應時間的要求,在這篇文章中,我會簡要的對HTTP/2協議進行介紹,然后我們將重點放在研究Java9中對HTTP/2支持及其HTTP客戶端API的變化,
一、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看起來不錯,但筆者覺得目前相關技術的使用還不是很成熟,我覺得大家暫時嘗嘗鮮就可以,
歡迎關注我的博客,里面有很多精品合集
- 本文轉載注明出處(必須帶連接,不能只轉文字):字母哥博客,
覺得對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創作動力! ,另外,筆者最近一段時間輸出了如下的精品內容,期待您的關注,
- 《手摸手教你學Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《實戰前后端分離RBAC權限管理系統》
- 《實戰SpringCloud微服務從青銅到王者》
- 《VUE深入淺出系列》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/195056.html
標籤:其他
下一篇:IDEA上運行Flink任務
