Java 原生 HTTP Client

​介绍

Java 原生 HttpClient 是从 Java 11 开始引入的标准库,用于简化 HTTP 请求的发送与响应处理。它支持同步和异步请求,并内置对 HTTP/1.1 和 HTTP/2 协议的支持。HttpClient 提供了易用的 API 来设置请求头、请求体、处理响应以及配置 SSL/TLS 加密等安全功能。


一个简单的例子

发送 GET 请求并将打印 Response

java 复制代码
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("http://localhost:8080/get")).GET().build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.statusCode());
System.out.println(response.headers());
System.out.println(response.body());

核心对象

HttpClient

要发送请求,首先需要通过其构建器创建一个 HttpClient 实例。构建器允许配置客户端的各种状态,例如 HTTP 协议版本、是否重定向、超时设置、代理、身份验证等等,从而定制每个客户端的行为。

java 复制代码
HttpClient client = HttpClient.newBuilder()
        .version(HttpClient.Version.HTTP_2)
        .followRedirects(HttpClient.Redirect.NORMAL)
        .proxy(ProxySelector.of(new InetSocketAddress("www-proxy.com", 8080)))
        .connectTimeout(Duration.ofMillis(200))
        .authenticator(Authenticator.getDefault())
        .build();

HttpRequest

HttpRequest 扮演着构建和配置 HTTP 请求的角色,,包括设置请求的 URL、请求方法(如 GET、POST、PUT 等)、请求头、请求体、超时时间等。HttpRequest 是不可变的,一旦创建后无法修改,只能通过 HttpRequest 的构建器来创建一个定制的请求对象。

java 复制代码
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("http://localhost:8080/get"))
        .GET()
        .build();

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("http://localhost:8080/post"))
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.noBody())
        .timeout(Duration.ofMinutes(1))
        .build();

HttpResponse

HttpResponse 用于表示 HTTP 请求的响应。它封装了 HTTP 响应的状态码、响应体、响应头、请求 URI、HTTP 协议版本等等。

HttpResponse 的常用方法

  • statusCode():获取 HTTP 响应的状态码。
  • body():获取响应体内容。
  • headers():获取所有响应头。
  • uri():获取响应对应的请求 URI。
  • version():获取响应使用的 HTTP 协议版本。

响应体的处理

响应体是通过 HttpResponse.BodyHandler 来处理的。HttpResponse.BodyHandler 是一个接口,用来定义如何处理响应体的内容。常用的 BodyHandler 有:

  • BodyHandlers.ofString():将响应体处理为字符串(适用于文本响应)
  • BodyHandlers.ofByteArray():将响应体处理为字节数组(适用于二进制数据,如文件下载)。
  • BodyHandlers.ofInputStream():将响应体处理为 InputStream(适用于流式处理)。
  • BodyHandlers.ofFile():将响应体直接写入文件(适用于文件下载等场景)。

同步和异步

同步

同步 HttpClient 通过调用 send() 方法来发送请求并等待响应。在请求完成之前,当前线程会被阻塞,即线程会等待直到 HTTP 响应返回并处理结果。

++上文给出的例子都是同步请求++

特点:

  • 阻塞:当前线程会等待直到请求完成并获取响应。
  • 顺序执行:代码会按顺序执行,每个请求都必须等待前一个请求完成。
  • 适用场景:适合较少的并发请求,或者请求和响应的顺序很重要时。

异步

通过调用 sendAsync() 方法来发送请求,该方法立即返回一个 CompletableFuture,而不是直接返回响应。请求会在后台线程中执行,主线程不会被阻塞。你可以使用 thenAccept()、thenApply() 等方法来处理响应。

特点:

  • 非阻塞:不会阻塞当前线程,任务在后台异步执行。
  • 并发执行:允许多个请求并行执行,可以提高效率,尤其是处理大量并发请求时。
  • 适用场景:适用于 I/O 密集型任务,如发送多个请求、等待多个响应时。
java 复制代码
HttpClient client = HttpClient.newBuilder().build();
HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("http://localhost:8080/get"))
        .GET()
        .build();

CompletableFuture<HttpResponse<String>> completableFutureResponse = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
HttpResponse<String> response = completableFutureResponse.get();

身份验证器

Authenticator 是 HttpClient 中用来为 HTTP 请求提供身份验证信息的核心类。Authenticator 的工作原理是基于 认证挑战(Authentication Challenge)机制。认证过程的基本步骤如下:

  1. 客户端发送请求:客户端向服务器发出一个 HTTP 请求,可能是没有认证信息的请求。
  2. 服务器返回认证挑战:如果目标资源需要认证,服务器会返回一个 401 Unauthorized 或 407 Proxy Authentication Required 响应,这两者都表明客户端没有提供有效的身份认证信息。
  3. Authenticator 触发:当 HttpClient 遇到需要认证的响应时,它会调用 Authenticator 的 getPasswordAuthentication() 方法。这是通过一个回调机制触发的,Authenticator 可以返回包含用户名和密码的 PasswordAuthentication 对象。
  4. 客户端再次发送带认证信息的请求:客户端将返回的认证信息(如用户名和密码)包含在 HTTP 请求的 Authorization 头部中,再次发送给服务器。
  5. 认证通过:如果服务器验证通过,返回相应的资源;否则验证失败。

注意:Authenticator 类的设计初衷是为了支持 HTTP 基本认证(Basic Authentication)和 代理认证(Proxy Authentication)等标准认证机制。对于 JWT 认证方式,并没有提供自动刷新。


参考

Introduction to the Java HTTP Client