1. 摘要
JEP 321 标准化了JDK 9引入孵化的HTTP Client(JEP 110)
2. 动机
JDK8中的HttpURLConnectionAPI及其实现存在许多问题:
- URLConnection API是设计时考虑了多种协议,几乎所有这些都是现在已经不存在(ftp,gopher,等)。
- API早于HTTP / 1.1并且过于抽象。
- 难于使用,很多没有文档化的行为
- 仅能在阻塞模式下工作
- 难于维护
3. 目标
HTTP Client的目标
- API必须是易于使用的,包括简单的阻塞模式
- 必须支持通知机制如HTTP消息头收到、错误码、HTTP消息体收到
- 简洁的API能够支持80-90%的需求
- 必须支持标准和通用身份验证机制
- 必须能够轻松使用WebSocket
- 必须支持HTTP 2
- 必须执行与现有网络API一致的安全检查
- 必须对lambda表达式等新语言功能很友好
- 应该对嵌入式系统友好,避免永久运行的后台线程
- 必须支持HTTPS / TLS
- 满足HTTP 1.1和HTTP 2的性能要求
4. 使用
4.1 Get
private static void testGet() {
var httpClient = HttpClient.newBuilder().build();
var request = HttpRequest.newBuilder().uri(URI.create("http://www.taobao.com")).build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
4.2 连接超时和socke read超时
var httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(3000))
.build();
var request = HttpRequest.newBuilder()
.timeout(Duration.ofMillis(3000))
.uri(URI.create("http://www.taobao.com"))
.build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
连接超时后,抛出java.net.http.HttpConnectTimeoutException: HTTP connect timed out
Socket读取超时后,抛出java.net.http.HttpTimeoutException: request timed out
4.3 设置HTTP header
var httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(3000))
.build();
var request = HttpRequest.newBuilder()
.timeout(Duration.ofMillis(3000))
.header("key1", "v1")
.header("key2", "v2")
.uri(URI.create("http://www.taobao.com"))
.build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
4.4 异步Get
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("http://www.taobao.com"))
.build();
var result = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);
try {
System.out.println(result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
异步请求通过CompletableFuture实现。
4.5 POST
String json = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
var httpClient = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("http://www.tabao.com"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
4.6 HTTP2
var httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(3000))
.version(HttpClient.Version.HTTP_2)
.build();
var request = HttpRequest.newBuilder()
.timeout(Duration.ofMillis(3000))
.header("key1", "v1")
.header("key2", "v2")
.uri(URI.create("https://www.google.com"))
.build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
System.out.println(response.version());
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
注意,由于HTTP 2协议的强制要求,如果目标URI是HTTP的,则无法使用HTTP 2协议。
4.7 异常处理
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder()
.uri(URI.create("http://127.0.0.1"))
.build();
var result = client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.exceptionally(e -> {
e.printStackTrace();
return "err: " + e.getMessage();
});;
try {
System.out.println(result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
exceptionally方法的入参是Function<T,R>
5. 结论
JDK 11中将HTTP Client从孵化版本升级为正式版本,正常情况下不再需要引入三方http client包。但是仍然没有对文件上传的原生支持,上传文件时仍然需要apache http client等三方包协助。