Java 原生 HTTP Client
介绍
Java 原生 HttpClient 是从 Java 11 开始引入的标准库,用于简化 HTTP 请求的发送与响应处理。它支持同步和异步请求,并内置对 HTTP/1.1 和 HTTP/2 协议的支持。HttpClient 提供了易用的 API 来设置请求头、请求体、处理响应以及配置 SSL/TLS 加密等安全功能。
一个简单的例子
发送 GET 请求并将打印 Response
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 协议版本、是否重定向、超时设置、代理、身份验证等等,从而定制每个客户端的行为。
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 的构建器来创建一个定制的请求对象。
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 密集型任务,如发送多个请求、等待多个响应时。
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)机制。认证过程的基本步骤如下:
- 客户端发送请求:客户端向服务器发出一个 HTTP 请求,可能是没有认证信息的请求。
- 服务器返回认证挑战:如果目标资源需要认证,服务器会返回一个 401 Unauthorized 或 407 Proxy Authentication Required 响应,这两者都表明客户端没有提供有效的身份认证信息。
- Authenticator 触发:当 HttpClient 遇到需要认证的响应时,它会调用 Authenticator 的 getPasswordAuthentication() 方法。这是通过一个回调机制触发的,Authenticator 可以返回包含用户名和密码的 PasswordAuthentication 对象。
- 客户端再次发送带认证信息的请求:客户端将返回的认证信息(如用户名和密码)包含在 HTTP 请求的 Authorization 头部中,再次发送给服务器。
- 认证通过:如果服务器验证通过,返回相应的资源;否则验证失败。
注意:Authenticator 类的设计初衷是为了支持 HTTP 基本认证(Basic Authentication)和 代理认证(Proxy Authentication)等标准认证机制。对于 JWT 认证方式,并没有提供自动刷新。
参考
Introduction to the Java HTTP Client