一、重大版本
Apache HttpClient 4.x 系列
• HttpClient 4.0(发布于2008年左右):这是一个重要的里程碑,标志着HttpClient从Jakarta Commons项目转移到Apache HttpComponents项目。4.0版进行了大量的重构,引入了新的连接管理模型(基于HttpCore),支持了HTTP/1.1的持久连接、连接池以及更灵活的配置选项。
• HttpClient 4.2(发布于2013年之前):此版本增加了对HTTP状态线支持、改进了多部分实体的处理、增强了请求参数编码,以及更强大的HTTP响应处理能力。它还引入了对国际域名(IDN)的支持,并改进了与SSL/TLS相关的功能。
• HttpClient 4.5(约2015年至2016年间):这个版本重点在于提升性能、增强安全性、简化API使用,并且开始为HTTP/2做准备。它包括对TLSv1.2的支持、改进的连接管理、更严格的SSL握手策略,以及对HTTP/2的初步实验性支持。
Apache HttpClient 5.x 系列
• HttpClient 5.0(2018年以后):这是一个重大的更新,引入了全新的HTTP/2实现,完全基于Java NIO,提供了原生的异步支持。此外,它还增强了对HTTP/1.1的性能和兼容性,改进了连接重用策略,支持了WebSocket,以及提供了更强大的请求和响应拦截器系统。
• 后续版本:随着时间的推移,HttpClient 5.x系列通过后续的小版本更新,继续优化HTTP/2支持、修复漏洞、提升性能和稳定性,并引入更多现代Web特性支持,如HTTP/3的实验性支持、对新TLS版本的兼容性增强等。
二、代码模块
httpclient
httpcore
httpcore-nio
httpasyncclient
1. HttpCore:
• 核心包:这是HttpClient库的基础,提供了HTTP协议的核心抽象和实现。它定义了HTTP请求、响应、头信息、实体内容、连接管理等基本组件。HttpCore分为两个模块:httpcore 用于NIO(非阻塞I/O)支持,而 httpcore-nio 专注于阻塞I/O模型。它是构建高性能HTTP客户端和服务端的基础。
2. HttpClient:
• 高级API:基于HttpCore,HttpClient提供了更高层次的API,使得发送HTTP请求变得简单直接。它封装了复杂的HTTP协议细节,让你可以专注于业务逻辑。HttpClient支持HTTPS、认证、连接管理、重定向处理、请求和响应实体的处理等特性。
3. HttpAsyncClient:
• 异步API:针对需要高性能和高并发的应用场景,HttpAsyncClient提供了异步请求处理能力。这意味着你可以在发送HTTP请求后立即返回,不阻塞当前线程,当响应到达时通过回调或Future/Promise模式处理结果。这非常适合那些需要处理大量并发请求的场景。
4. Connection Management:
• 连接池管理:HttpClient支持通过ConnectionManager(如PoolingHttpClientConnectionManager)来复用连接,减少每次请求时建立和销毁TCP连接的开销。连接池管理包括连接的最大数量、超时设置、空闲连接的清理等,对于性能优化至关重要。
5. Request and Response Handling:
• 请求与响应处理:HttpClient提供了丰富的API来构建HTTP请求(如GET、POST、PUT等)、设置请求头、处理请求体、解析响应等。它还支持多种实体处理器(EntityHandler)来处理不同类型的内容,如字符串、文件、流等。
6. Authentication and Authorization:
• 认证与授权:支持多种认证机制,包括Basic、Digest、NTLM、Kerberos以及OAuth等,以满足不同安全需求。
7. Redirects and Retries:
• 重定向与重试:自动处理HTTP重定向,并且可以配置重试策略来处理暂时性的网络问题或服务器错误。
8. SSL/TLS Support:
• SSL/TLS支持:HttpClient能够处理HTTPS请求,并允许自定义SSL上下文以支持信任管理、证书验证等安全配置。
9. Interceptors and Filters:
• 拦截器与过滤器:允许插入自定义逻辑到请求/响应处理流程中,例如日志记录、请求/响应修改、计时、性能监控等。
10. Content Compression:
• 内容压缩:支持请求和响应内容的自动压缩,减少网络传输的数据量,提升效率。
三、设计哲学
CloseableHttpClient 上层使用入口,通过HttpClients工具生产
HttpClientConnectionManager 连接管理,最大连接数,单路由最大连接数
RequestConfig 请求配置,连接超时时间,读取超时时间
在Spring框架中,Spring为RestTemplate设计了兼容类,org.springframework.http.client.HttpComponentsClientHttpRequestFactory
用来直接接收HttpClient。这样就完美结合了RestTemplate和Apache HttpClient
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
public class HttpClientPoolUtil {
private static final int MAX_TOTAL_CONNECTIONS = 100;
private static final int DEFAULT_MAX_PER_ROUTE = 20;
private static final int CONNECT_TIMEOUT = 5000; // 连接超时时间,单位毫秒
private static final int SOCKET_TIMEOUT = 10000; // 数据读取超时时间,单位毫秒
private static volatile CloseableHttpClient httpClient;
private static PoolingHttpClientConnectionManager connectionManager;
private HttpClientPoolUtil() {
// 防止外部实例化
}
private static synchronized void init() {
if (httpClient != null) {
return;
}
connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(CONNECT_TIMEOUT)
.setSocketTimeout(SOCKET_TIMEOUT)
.build();
httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(config)
.build();
}
public static String sendGetRequest(String url) throws Exception {
if (httpClient == null) {
init();
}
HttpGet httpGet = new HttpGet(url);
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toString(entity);
} else {
throw new RuntimeException("Response entity is null");
}
}
}
// 可以根据需要添加其他HTTP方法如POST、PUT等
}
public class Main {
public static void main(String[] args) {
try {
String response = HttpClientPoolUtil.sendGetRequest("http://example.com/api/data");
System.out.println(response);
} catch (Exception e) {
e.printStackTrace();
}
}
}