新的 HTTP 客户端 API - Java 细品

需要通过 HTTP 发送或接收来自远程服务的数据吗?JDK 11 中添加的 HTTP 客户端改进了并替换了 HttpUrlConnection API。在本文中,我们将探讨如何使用新的 HttpClient 以及它提供的一些 HttpUrlConnection 不具备的新功能。

HttpClient 概述

HTTP 客户端是在 JDK 11 中添加的,之前作为 JDK 9 中的孵化器功能引入。HTTP 客户端的目标是替换 HttpUrlConnection,它不仅 API 难以使用,而且不支持 HTTP/2 和 WebSocket 等协议。

HTTP 客户端通过提供对 HTTP/2 和 WebSocket 的支持、更易于使用的 API 以及添加异步调用和响应式流等新功能来解决这些缺点。

创建客户端

通过其构建器 API 创建 HttpClient 的新实例

HttpClient client = HttpClient.newBuilder()
	.version(Version.HTTP_1_1)
	.followRedirects(Redirect.NORMAL)
	.connectTimeout(Duration.ofSeconds(20))
	.proxy(ProxySelector.of(...))
	.authenticator(Authenticator.getDefault())
	.build();

newBuilder() 有用于设置属性的方法,例如:HTTP 版本、重定向行为、代理、超时、身份验证器等等。创建后,HttpClient 是不可变的。

创建请求

HttpClient 一样,HttpRequest 也是通过其构建器 API 创建的

HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://openjdk.org/"))
      .timeout(Duration.ofSeconds(10))
      .header("Content-Type",
      	"application/json")
      .GET()
      .build()

newBuilder() 提供用于设置属性的方法,例如:URI、超时、标头、HTTP 方法等等。与 HttpClient 一样,HttpRequest 是不可变的;但是,请求可以多次使用。

## 发送请求

请求可以作为同步阻塞调用或异步非阻塞调用发送。

同步请求

HttpResponse<String> response =
      client.send(request, 
      	BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());

异步请求

client.sendAsync(request, 
	BodyHandlers.ofString())
      .thenApply(response -> 
      	{ System.out.println
      		(response.statusCode());
               return response; 
       } )
      .thenApply(HttpResponse::body)
      .thenAccept(System.out::println);

响应式流

异步请求也可以用作响应式流。作为响应式流,HttpRequest 充当发布者,HttpResponse 充当订阅者,其类中包含用于处理流的相应方法

public abstract class HttpRequest {
    ...
    public interface BodyPublisher
        extends Flow.Publisher<ByteBuffer> 
        	{ ... }
}

public abstract class HttpResponse<T> {
    ...
    public interface BodyHandler<T> {
        BodySubscriber<T> 
        	apply(int statusCode, 
        	HttpHeaders responseHeaders);
    }

    public interface BodySubscriber<T>
        extends 
        	Flow.Subscriber<List<ByteBuffer>> 
        { ... }
}

其他阅读资料

编码愉快!