1.简介
IETF流媒体小组于2015年(即HTTP / 1.1发布后的16年) 批准了HTTP / 2协议。 HTTP / 2有望降低延迟,并且使许多替代方法变得过时,而这些替代方法是HTTP / 1.1所必需的,以便能够满足当今的响应时间要求。 在本文中,我将简要介绍HTTP / 2以及它如何更新基于文本的HTTP / 1.1,然后研究Java 9中即将推出的HTTP / 2支持。
2. HTTP / 1.1的延迟优化技术
人们越来越多地在Internet上住院,但是他们不会注意到,如果响应时间低于100毫秒,那么他们在网络上执行的操作并不是直接由他们自己执行的。
当响应时间达到1秒并引起注意,并且网站响应时间超过10秒时,就被认为是混乱的。 根据一些研究 ,平均注意力跨度已降至7-8秒,即使延迟1秒也可能导致7%的收入损失。
HTTP / 1.1需要(有时很繁重)的变通办法来满足当今的要求。
- 由于一个HTTP连接一次可以下载一个资源,因此浏览器会同时获取它们,以便能够更快地呈现页面。 但是,每个域的并行连接数是有限的,并且使用域分片来解决该问题。
- 一种类似的优化技术是将多个资源(CSS,JavaScript)组合到一个包中,以便能够通过单个请求获取它们。 权衡使网络往返的时间减少了,而根本没有使用组装好的资源束中某些部分的风险。 在某些情况下,复杂的服务器端逻辑会负责选择相关的静态资源并将其合并为特定的页面请求
- 图像精灵是一种类似于将CSS和JavaScript文件捆绑在一起以减少请求数量的技术。
- 另一种技术的存在是在衬里静态资源HTML
3. HTTP / 2简介
HTTP / 2旨在减轻因维护HTTP / 1.1的复杂基础结构以使其正常运行而引起的痛苦。 尽管HTTP / 2仍与HTTP / 1.1向后兼容,但它不再是基于文本的协议。 客户端将连接建立为HTTP / 1.1请求,然后请求并升级。 从那以后,HTTP / 2在二进制数据帧中对话。
HTTP / 2复用
HTTP / 2复用使上述所有HTTP / 1.1解决方法都已过时,因为单个连接可以处理多个双向流,因此允许客户端同时通过单个连接下载多个资源。
HTTP 1.x协议基于文本,因此很冗长。 有时,一次又一次地交换同一组HTTP标头。 HTTP / 2通过在请求之间维护HTTP标头表,大大减少了所需的带宽。 本质上,这是重复数据删除,而不是传统意义上的压缩。
HTTP / 2推送
您可能会认为HTTP / 2推送是WebSocket的延续或某种升级,但事实并非如此。 WebSocket是在客户端和服务器之间进行全双工通信的一种方法,以便在建立TCP连接后允许服务器将数据发送到客户端,而HTTP / 2则解决了另一个问题。
HTTP / 2推送是关于主动向客户端发送资源,而不必从客户端的角度要求它。 实际上,这意味着服务器端知道一个网站需要一些图像,并且在客户端请求它们之前很长一段时间(一次)将它们全部发送出去。
4.支持HTTP / 2的Java HTTP客户端
根据HTTP / 2的Wiki页面之一,在编写本文时,以下Java客户端库可用于建立HTTP / 2连接。
- 码头
- 净额
- OkHttp
- Vert.x
- 萤火虫
但是,在本文中,我们重点关注Java 9提供的HTTP / 2支持。JEP110指定了要求,并且还指出该项目仍处于孵化状态,这实际上意味着该项目将不会取代现有的UrlConnection。 Java 9中的API
仅在Java 10中,标准Java HTTP / 2客户端才会移动到包java.net下 。 但是,与此同时,它将位于jdk.incubtor
命名空间下。
5.探索Java 9的HTTP / 2客户端
JEP 110设置了对新的内置HTTP / 2客户端的要求,以便它提供高级,易于使用的API,并且与现有的替代产品相比具有可比的(或更高的)性能(请参见上文)。
第一步是导入模块jdk.incubator.httpclient
。
module com.springui.echo.client {requires jdk.incubator.httpclient;
}
为了这个示例,我们将使用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随处都遵循构建器模式,而HttpClient是发起HTTP请求的入口,也不例外。
HttpClient client = HttpClient.newBuilder().version(Version.HTTP_2).build();
以阻止模式发送请求
一旦有了HttpClient实例,也可以使用构建器构造HttpRequest实例。
HttpResponse<String> response = client.send(HttpRequest.newBuilder(TEST_URI).POST(BodyProcessor.fromString("Hello world")).build(),BodyHandler.asString()
);
只要请求得到处理,方法send块就会发送 ,但是也有一种异步交换HTTP消息的方法。
以非阻塞模式发送请求
在下面的示例中,将10个随机整数异步发送到我们的HTTP回显服务器,并且在所有请求都已发起后,主线程等待它们完成。
List<CompletableFuture<String>> 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));
});
处理承诺框架
上面所有示例都可能是常规的老式HTTP / 1.1请求。 除了创建HttpClient之外 ,无法观察到任何特定于HTTP / 2的内容。
客户端API最相关的HTTP / 2功能可能是使用HTTP / 2推送时它处理多个响应的方式。
Map<HttpRequest, CompletableFuture<HttpResponse<String>>> 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支持,则可以使用上述上述库。
更新: HTTP客户端JEP 312提议对HTTP客户端API进行标准化,该HTTP客户端API是在Java 9中作为孵化API引入的,并在Java 10中进行了更新。从Java 11开始,它是java.net
模块的完整功能。
如果您想了解有关Java 9的更多信息,还可以从Java Code Geeks中查看这些Java 9教程 。
翻译自: https://www.javacodegeeks.com/2020/01/introduction-to-http-2-support-in-java-9.html