JEP 321: HTTP Client 在 JDK 11 正式交付。
新的 HTTP Client 代替了传统的贼难用的 HttpUrlConnection 类成为 Java 内建的 HTTP 客户端。
HttpUrlConnection 已经服役多年,略显老态。
新的 HTTP Client 提供了新的特性,例如:
HttpClient httpClient = HttpClient.newBuilder().build();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://nghttp2.org/httpbin/get"))
.version(Version.HTTP_2)
.GET()
.build();
HttpResponse<String> resp = httpClient.send(req, BodyHandlers.ofString());
System.out.printf("Status: %s\nBody: %s%n", resp.statusCode(), resp.body());
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://nghttp2.org/httpbin/get"))
.version(Version.HTTP_2)
.GET()
.build();
CompletableFuture<HttpResponse<String>> response = httpClient.sendAsync(
req, BodyHandlers.ofString());
response.thenAcceptAsync((resp) -> {
System.out.printf("Status: %s\nBody: %s%n", resp.statusCode(), resp.body());
})
.get();
HttpRequest.newBuilder()
.uri(URI.create("https://nghttp2.org/httpbin/get"))
.GET()
.build();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/anything"))
.POST(HttpRequest.BodyPublishers.ofString("""
{
"message": "Hello, world!"
}
"""
))
.build();
新的 API 确实好用了很多。但是又没有真的很符合直观。
指定 url 的时候只有 HttpRequest.newBuilder().uri()
可用,开发者必须自己 URI.create("https://nghttp2.org/httpbin/get")
。
就用户体验来说,最常用的传入字符串的操作反而不支持,令人迷惑。
另外,不管同步还是异步,httpclient 都要求传入 BodyHandler 作为第二入参。
跟 Stream API 的 collect() 一个风格,开发者此处可以通过 BodyHandlers.ofXXX() 方法获取 Java 自带的 BodyHandlers。
BodyHandler 负责将 HTTP 响应转换成想要的形式。
例如 BodyHandlers.ofString()、BodyHandlers.ofFile()、BodyHandlers.ofLines() 和 BodyHandlers.ofByteArray() 等等。
这确实极大地方便开发者。但是把这个功能抽象成 send() 方法的第二参数,真是一股 Java 的老派味道😂。
另外,现代的 http client 提供的特性在 jdk 自带的 http client 上也看不到。
例如 --http2-prior-knowledge 节省协议协商的过程、HTTP/2 Cleartext 似乎也不支持。