您的位置:首頁>科技>正文

Java 9 HTTP/2的支援功能前瞻

Java 9預期將於本月27日發佈, 本文由László Csontos發佈在Springuni, 討論了Java 9與HTTP/2有關的特性。

在HTTP/1.1發佈後16年, 國際互聯網工程任務組(IETF)的流媒體工作組在2015年批准了HTTP/2協議。 HTTP/2承諾降低網路延遲, 並棄用很多在HTTP/1.1中所必需的工作流程, 以滿足當今的回應時間要求。 本文將簡要介紹HTTP/2, 並談談它是怎樣使基於文本的HTTP/1.1變得煥然一新的, 以及即將來到的Java 9中對HTTP/2的支援功能。

HTTP/1.1早已變得老舊不堪, 而1999年以來的互聯網已經發生了很多變化。

在互聯網上, 人們正變得越來越沒有耐心, 但他們不會注意到, 如果回應時間低於100毫秒, 那麼他們在網路上表現出的行為並不直接由他們自己實施。

當響應時間達到1秒時, 就會引起人們的注意了, 而當一個網站的響應時間超過10秒時, 那麼它就會被認為發生了故障。 根據一些調查的結果, 人們注意力的平均持續時間已經下降到7-8秒, 所以即使是1秒的延遲也會造成高達7%的收入損失。

針對HTTP/1.1的網路延遲優化技術

對於HTTP/1.1來說, 需要做一些(有時候是很繁重的)工作來滿足當今的要求。

一項類似的優化技術是將多個資源(CSS、JavaScript)捆綁在一起, 這樣就能夠通過一次單獨的請求獲取到這些資源。 這樣做好壞參半, 在節省了一次網路往返過程的同時, 可能會使捆綁資源中的一部分無法使用。 在某些情況下, 複雜的伺服器端邏輯負責選擇適當的靜態資源,

並將它們合併以回應特殊的頁面請求。

Image sprites圖像精靈是一項與CSS和JavaScript檔捆綁類似的技術, 可以減少請求的數量。

還有另一項技術被用於將靜態資源內嵌到HTML中。

HTTP/2概述

HTTP/2意在減輕為維護HTTP/1.1複雜的底層架構而帶來的痛苦, 以提高HTTP/1.1的性能。 儘管HTTP/2仍然對HTTP/1.1向下相容, 但它已不再是一個基於文本的協定。 當用戶端通過HTTP/1.1請求建立一個連接時, 所有請求將會被升級。 從這一點上看, HTTP/2是用“二進位資料幀”來說話的。

HTTP/2多工

HTTP/2頭部壓縮

HTTP 1.x協定族都是基於文本的, 因此它們都相當冗長。 有時候同一個HTTP頭的集合被一遍又一遍地進行交換。 HTTP/2在整個請求過程中保持HTTP頭 表不變, 因而大大降低了所需的頻寬。 重要的是, 這只是在去耦合, 而不是經典意義上的壓縮。

HTTP/2推送

你可能會認為, HTTP/2推送是某種WebSocket的延續或升級, 但實際上並不是這樣。 WebSocket是用戶端和伺服器之間全雙工通信的一種方法, 一旦TCP連接被建立起來, 伺服器就可以向用戶端發送資料, 而HTTP/2則解決的是與此不同的問題。

HTTP/2推送一種主動向用戶端發送資源的技術, 不必由用戶端發出請求。 這實際上意味著, 伺服器端知道, 一個網站需要一些圖片, 伺服器會在用戶端發出請求前的很長時間內, 就一次性將這些圖片發送到用戶端。

Java HTTP用戶端支援HTTP/2

根據維琪百科關於HTTP/2的一個頁面的說法, 在編寫的時候, 以下Java用戶端庫已能夠建立HTTP/2連接。

Jetty

Netty

OkHttp

x

Firefly

但在這篇文章中, 我們關注的是Java 9提供的HTTP/2支持。 JEP 110 指定了具體要求, 同時聲明該專案仍處於孵化狀態, 這實際上意味著,

它將不會取代Java 9中現有的UrlConnection API。 只有在Java 10發佈後, 標準Java HTTP/2用戶端才會被移動到java.net包之下。 但同時, 它會處於jdk.incubtor命名空間下。

JEP 110為新的、內置的HTTP/2用戶端提出了具體要求, 因此它提供了一個高級別的、簡便易用的API和與現有選項相似(或更高)的性能。

第一步是導入模組jdk.incubator.httpclient。

1、module com.springui.echo.client {

2、requires jdk.incubator.httpclient;

3、}

對於這個例子來說, 我們要使用Undertow做為相容HTTP/2的web伺服器。 它用來回應用戶端發送的消息。

public class EchoServer {

private static final Logger LOGGER = Logger.getLogger(EchoServer.class.getSimpleName());

private static final int PORT = 8888;

private static final String HOST = “localhost”;

public static void main(final String[] args) {

Undertow server = Undertow.builder()

.setServerOption(UndertowOptions.ENABLE_HTTP2, true)

.addHttpListener(PORT, HOST)

.setHandler(exchange -> {

LOGGER.info(“Client address is: ” + exchange.getConnection().getPeerAddress().toString());

exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, “text/plain”);

exchange.getRequestReceiver().receiveFullString((e, m) -> e.getResponseSender().send(m));

}).build();

server.start();

}

}

新的API處處遵循生成器模式, 而作為初始化HTTP請求入口的HttpClient也不例外。

HttpClient client = HttpClient

.newBuilder()

.version(Version.HTTP_2)

.build();

一旦我們有了一個HttpClient實例, 就可以通過一個生成器建立更多的HttpClient實例。

以阻塞模式發送請求

HttpResponse response = client.send(

HttpRequest

.newBuilder(TEST_URI)

.POST(BodyProcessor.fromString(“Hello world”))

.build(),

BodyHandler.asString()

);

以非阻塞模式發送請求

請求被處理多久, send方法就會阻塞多久, 但還是有一種方法來非同步交換HTTP消息:以非阻塞模式發送請求。

在下面的例子中,

10個隨機整數被非同步發送到我們的HTTP回顯伺服器, 而當所有請求被初始化後, 主執行緒等待它們完成。

List responseFutures = new Random()

.ints(10)

.mapToObj(String::valueOf)

.map(message -> client

.sendAsync(

HttpRequest.newBuilder(TEST_URI)

.POST(BodyProcessor.fromString(message))

.build(),

BodyHandler.asString()

)

.thenApply(r -> r.body())

)

.collect(Collectors.toList());

CompletableFuture.allOf(responseFutures.toArray(new CompletableFuture[0])).join();

responseFutures.stream().forEach(future -> {

LOGGER.info(“Async response: ” + future.getNow(null));

});

處理push-promise架構

以上全部例子都可以是過時的HTTP/1.1請求。 除了創建HttpClient以外, 沒有看到任何HTTP/2所特有的東西。

這個用戶端API中與HTTP/2最有關聯的功能很可能是當HTTP/2推送被使用時它處理多個回應的方式。

Map> responses =

client.sendAsync(

HttpRequest.newBuilder(TEST_URI)

.POST(BodyProcessor.fromString(TEST_MESSAGE))

.build(),

MultiProcessor.asMap(request -> Optional.of(BodyHandler.asString()))

).join();

responses.forEach((request, responseFuture) -> {

LOGGER.info(“Async response: ” + responseFuture.getNow(null));

});

HTTP/2進行了一些必要改進, 使舊的基於文本的協定變得煥然一新, 並拋棄了令人討厭的HTTP/1.1中的很多工作流程, 但是它並未解決所有已知的問題。

結論

從Java 9方面來看, 新的HTTP/2用戶端貌似不錯, 但它的下一個版本才會是合格的產品。 同時, 如果需要HTTP/2支援的話, 上面的庫都可以使用。

來自SSL中國

文章轉載:https://www.trustauth.cn/news/security-news/18897.html

Next Article
喜欢就按个赞吧!!!
点击关闭提示