☕️从小工到专家的 Java 进阶之旅:全新的HttpClient,现代高效的网络通信利器
你好,我是看山。
本文收录在 《从小工到专家的 Java 进阶之旅》 系列专栏。日拱一卒,功不唐捐。
在 Java 开发领域,网络通信一直是至关重要的部分。从早期的网络编程方式到如今,Java 在 HTTP 客户端方面经历了不断的演进。
其中,Java11 中正式推出的全新 HttpClient 带来了许多令人瞩目的变化。
一、Java HttpClient 的演进历程
在 Java 的发展历程中,HttpURLConnection 是早期进行 HTTP 通信的主要方式之一。然而,随着网络应用的日益复杂和对性能、功能的更高要求,它逐渐暴露出一些局限性。
传统的 HttpURLConnection 在处理复杂的网络交互场景时,代码编写相对繁琐,缺乏一些现代网络编程所需要的特性。例如,在异步处理、高效的并发操作以及对新的 HTTP 协议版本的支持方面表现不够理想。
而全新的 HttpClient 则应运而生,它是 Java 为了满足现代网络应用开发需求而设计的新一代 HTTP 客户端库。它的出现标志着 Java 在网络通信领域迈向了一个新的阶段,为开发者提供了更强大、更高效、更灵活的网络编程工具。
二、新 HttpClient 的特点与优势
(一)强大的功能特性
-
支持多种协议版本
- 新的 HttpClient 同时支持 HTTP/1.1 和 HTTP/2。HTTP/2 相比 HTTP/1.1 在性能上有显著的提升,它通过多路复用、头部压缩等技术,减少了网络延迟,提高了数据传输效率。
- 对于安全的网络通信,它也很好地支持了 HTTPS/TLS 协议,确保数据在传输过程中的安全性和完整性。
-
异步发送与通知机制
- 支持异步操作是新 HttpClient 的一个重要特性。通过异步发送请求,应用程序可以在等待服务器响应的同时执行其他任务,提高了程序的并发处理能力。
- 当异步请求完成时,客户端可以通过通知机制及时获取响应结果,这种机制使得程序的响应性更加出色。
-
WebSocket 支持
- WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。新 HttpClient 对 WebSocket 的支持使得 Java 应用程序能够轻松地构建实时的、双向通信的网络应用,如即时通讯、实时数据推送等。
-
响应式流
- 响应式流是一种处理异步数据流的编程模型。新 HttpClient 与响应式流的集成,使得开发者可以更加高效地处理大量的异步数据,比如在处理实时数据更新或者大数据流传输的场景下,能够实现更平滑的数据处理和更低的资源消耗。
(二)简洁易用的 API
-
链式调用和流式操作
- 新 HttpClient 的 API 设计非常简洁,它大量采用了链式调用和流式操作的方式。例如,在构建请求时,可以通过链式调用连续地设置请求方法、请求头、请求体等信息,使得代码更加清晰、简洁,易于理解和维护。
- 这种设计模式符合现代编程的习惯,提高了开发效率。
-
与现有网络 API 一致的安全检查
- 在安全方面,新 HttpClient 与 Java 现有的网络安全 API 保持了一致。它继承了 Java 安全模型的优势,在进行网络请求时,能够自动进行必要的安全检查,如证书验证、权限检查等,确保网络通信的安全可靠。
(三)高效的性能表现
-
NIO 模型
- 新 HttpClient 基于 NIO(Non - Blocking I/O)模型进行设计。NIO 模型能够在一个线程中处理多个连接,避免了传统阻塞 I/O 模型中线程被阻塞等待 I/O 操作完成的情况。
- 这使得新 HttpClient 在高并发场景下能够高效地利用系统资源,大大提高了程序的吞吐量和响应速度。
-
函数式编程
- 函数式编程的思想在新 HttpClient 中得到了充分的体现。通过使用函数式接口和 Lambda 表达式,开发者可以更加简洁地定义请求处理逻辑、响应处理逻辑等,减少了代码的冗余和复杂性。
-
CompletableFuture 异步回调
- CompletableFuture 是 Java 8 引入的一个用于异步编程的类。新 HttpClient 利用 CompletableFuture 实现异步回调机制,使得开发者可以方便地在异步操作完成后执行后续的处理逻辑。
- 这种异步回调机制能够有效地避免阻塞,提高程序的并发性能。
三、新 HttpClient 的使用方法
(一)同步请求
以下是一个简单的同步请求的示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;public class HttpClientSyncExample {public static void main(String[] args) throws Exception {// 创建 HttpClient 对象HttpClient httpClient = HttpClient.newHttpClient();// 构建 HttpRequestHttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com")).GET().build();// 发送请求并获取 HttpResponseHttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());System.out.println("Response status code: " + httpResponse.statusCode());System.out.println("Response body: " + httpResponse.body());}
}
在上述示例中,首先通过HttpClient.newHttpClient()
创建了一个 HttpClient 对象。然后使用HttpRequest.newBuilder()
构建了一个 GET 请求,并指定了请求的 URL。最后通过httpClient.send()
方法发送请求并获取响应。
(二)异步请求
异步请求的示例如下:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;public class HttpClientAsyncExample {public static void main(String[] args) throws Exception {// 创建 HttpClient 对象HttpClient httpClient = HttpClient.newHttpClient();// 构建 HttpRequestHttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com")).GET().build();// 发起异步请求并处理结果CompletableFuture<HttpResponse<String>> futureResponse = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());futureResponse.thenApply(response -> {System.out.println("Response status code: " + response.statusCode());System.out.println("Response body: " + response.body());return response;}).exceptionally(ex -> {System.out.println("Error occurred: " + ex.getMessage());return null;});// 主线程可以继续执行其他任务System.out.println("Main thread is doing other things...");// 等待异步操作完成futureResponse.join();}
}
在这个示例中,通过httpClient.sendAsync()
方法发起异步请求,返回一个CompletableFuture
对象。然后通过thenApply()
方法在请求成功完成时处理响应,通过exceptionally()
方法处理异常情况。
(三)发送 POST 请求
发送 POST 请求时,通常需要设置请求体。以下是一个示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;import java.nio.charset.StandardCharsets;public class HttpClientPostExample {public static void main(String[] args) throws Exception {HttpClient httpClient = HttpClient.newHttpClient();String requestBody = "data to be sent in the POST request";HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com/api")).POST(HttpRequest.BodyPublishers.ofString(requestBody, StandardCharsets.UTF_8)).header("Content-Type", "application/json").build();HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());System.out.println("Response status code: " + httpResponse.statusCode());System.out.println("Response body: " + httpResponse.body());}
}
在这个示例中,使用HttpRequest.BodyPublishers.ofString()
方法设置了请求体,并指定了字符编码。同时,还设置了请求头中的Content - Type
为application/json
。
(四)处理响应体
除了使用HttpResponse.BodyHandlers.ofString()
来获取字符串形式的响应体,还可以使用其他的响应体处理器。例如,HttpResponse.BodyHandlers.ofByteArray()
可以获取字节数组形式的响应体,HttpResponse.BodyHandlers.ofInputStream()
可以获取输入流形式的响应体。
以下是一个使用HttpResponse.BodyHandlers.ofByteArray()
的示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;public class HttpClientResponseBodyExample {public static void main(String[] args) throws Exception {HttpClient httpClient = HttpClient.newHttpClient();HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com/image.jpg")).GET().build();HttpResponse<byte[]> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofByteArray());byte[] responseBody = httpResponse.body();// 可以对字节数组形式的响应体进行进一步处理,比如保存为文件等}
}
(五)设置超时和重定向策略
可以自定义 HttpClient 的配置来设置超时时间和重定向策略。
设置超时时间的示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;import java.time.Duration;public class HttpClientTimeoutExample {public static void main(String[] args) throws Exception {HttpClient httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build();HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com")).GET().build();HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());System.out.println("Response status code: " + httpResponse.statusCode());System.out.println("Response body: " + httpResponse.body());}
}
在这个示例中,通过HttpClient.newBuilder().connectTimeout()
方法设置了连接超时时间为 5 秒。
设置重定向策略的示例:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;import java.net.http.HttpClient.Redirect;public class HttpClientRedirectExample {public static void main(String[] args) throws Exception {HttpClient httpClient = HttpClient.newBuilder().followRedirects(Redirect.NEVER).build();HttpRequest httpRequest = HttpRequest.newBuilder().uri(URI.create("http://example.com/redirect")).GET().build();HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());System.out.println("Response status code: " + httpResponse.statusCode());System.out.println("Response body: " + httpResponse.body());}
}
在这个示例中,通过HttpClient.newBuilder().followRedirects()
方法设置了重定向策略为从不重定向。
四、新 HttpClient 的未来展望
新 HttpClient 在 Java 网络通信中已经占据了重要的地位。随着 Java 技术的不断发展以及网络应用场景的不断拓展,它未来的发展方向和应用前景值得期待。
在未来,新 HttpClient 可能会进一步优化性能,尤其是在高并发、大数据量传输等极端场景下。它可能会与 Java 的其他新特性,如虚拟线程等进行更好的结合,以提供更加高效、稳定的网络通信能力。
在应用领域方面,新 HttpClient 将在微服务架构、分布式系统、物联网等领域发挥更大的作用。例如,在微服务架构中,服务之间的高效通信是关键,新 HttpClient 可以为服务间的 HTTP 调用提供更好的性能和可靠性。在物联网领域,大量的设备需要与服务器进行网络通信,新 HttpClient 可以满足物联网设备对高效、低资源消耗的网络通信的需求。
总之,Java 全新 HttpClient 是一个强大、高效、灵活的网络通信工具,它为 Java 开发者在现代网络应用开发中提供了有力的支持。随着它的不断发展和完善,相信它将在更多的领域得到广泛的应用。
文末总结
本文介绍了Java11提供的新版HttpClient
的功能,在后续的开发过程中,我们就有了更多的选择。
青山不改,绿水长流,我们下次见。
推荐阅读
- 从小工到专家的 Java 进阶之旅
- 一文掌握 Java8 Stream 中 Collectors 的 24 个操作
- 一文掌握 Java8 的 Optional 的 6 种操作
- 使用 Lambda 表达式实现超强的排序功能
- Java8 的时间库(1):介绍 Java8 中的时间类及常用 API
- Java8 的时间库(2):Date 与 LocalDate 或 LocalDateTime 互相转换
- Java8 的时间库(3):开始使用 Java8 中的时间类
- Java8 的时间库(4):检查日期字符串是否合法
- Java11 中基于嵌套关系的访问控制优化