一,简介
Apache HttpClient 是 Java 中的一个强大且广泛使用的 HTTP 客户端库,用于发送 HTTP 请求(如 GET、POST 等)并与 HTTP 服务器进行交互。它是 Apache Software Foundation 下的开源项目,属于 HttpComponents 项目的一部分。
主要特性
- 支持 HTTP 协议
- 完整支持 HTTP/1.1 和 HTTP/2,兼容 RFC 标准。
- 提供同步(阻塞)和异步(非阻塞)的请求方式。
- 连接管理
- 内置连接池(PoolingHttpClientConnectionManager),复用连接提升性能。
- 支持多线程环境下的并发请求。
- 灵活的 API
- 可定制请求头、参数、超时时间、代理等。
- 支持 HTTPS、Cookie、重定向、身份认证(Basic、Digest、NTLM 等)。
- 扩展性
- 支持拦截器(Interceptor),可在请求/响应前后插入自定义逻辑。
- 可集成 JSON/XML 解析库(如 Jackson、Gson)。
核心组件
HttpClient
发送请求的核心接口,通常通过HttpClientBuilder
创建。HttpRequest
表示 HTTP 请求(如HttpGet
、HttpPost
)。HttpResponse
封装服务器返回的响应(状态码、响应体、头信息等)。EntityUtils
工具类,用于处理响应实体(如将响应体转为字符串)。
二,快速入门
-
添加依赖
<dependency> <groupId>org.apache.httpcomponents.client5</groupId> <artifactId>httpclient5</artifactId> <version>5.3.1</version> </dependency>
-
发送 GET 请求
```java
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;
public class QuickStart {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 2. 创建 GET 请求
HttpGet request = new HttpGet("https://jsonplaceholder.typicode.com/posts/1");
// 3. 发送请求并获取响应
try (CloseableHttpResponse response = httpClient.execute(request)) {
// 4. 解析响应内容
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Response: " + responseBody);
// 5. 获取状态码
System.out.println("Status Code: " + response.getCode());
}
}
}
}
```
3. 发送 POST 请求(JSON 数据)
```java
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.EntityBuilder;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.StringEntity;
public class PostExample {
public static void main(String[] args) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost request = new HttpPost("https://jsonplaceholder.typicode.com/posts");
// 设置 JSON 请求体
String jsonBody = "{\"title\":\"foo\", \"body\":\"bar\", \"userId\":1}";
request.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));
// 发送请求
try (CloseableHttpResponse response = httpClient.execute(request)) {
System.out.println(EntityUtils.toString(response.getEntity()));
System.out.println("Status Code: " + response.getCode());
}
}
}
}
```
4. 发送Put请求
```java
import org.apache.hc.client5.http.classic.methods.HttpPut;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
public class PutRequestExample {
public static void main(String[] args) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 1. 创建 PUT 请求
HttpPut putRequest = new HttpPut("https://jsonplaceholder.typicode.com/posts/1");
// 2. 设置 JSON 请求体
String jsonBody = "{\"title\":\"Updated Title\", \"body\":\"New content\", \"userId\":1}";
putRequest.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));
// 3. 可选:设置请求头
putRequest.setHeader("Accept", "application/json");
// 4. 发送请求并处理响应
try (CloseableHttpResponse response = httpClient.execute(putRequest)) {
System.out.println("状态码: " + response.getCode());
System.out.println("响应体: " + EntityUtils.toString(response.getEntity()));
}
}
}
}
5. 发送DELETE请求
```java
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;
public class DeleteRequestExample {
public static void main(String[] args) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 1. 创建 DELETE 请求
HttpDelete deleteRequest = new HttpDelete("https://jsonplaceholder.typicode.com/posts/1");
// 2. 可选:设置请求头
deleteRequest.setHeader("Authorization", "Bearer token123");
// 3. 发送请求并处理响应
try (CloseableHttpResponse response = httpClient.execute(deleteRequest)) {
System.out.println("状态码: " + response.getCode());
if (response.getEntity() != null) {
System.out.println("响应体: " + EntityUtils.toString(response.getEntity()));
} else {
System.out.println("资源已删除,无响应体");
}
}
}
}
}
三,扩展功能
3.1 设置超时时间
超时时间的设置在HttpClient中非常重要,可以防止请求因为网络问题或服务器响应过慢而无限期地挂起。超时时间主要分为两种
-
连接超时时间(Connection Timeout)
连接超时时间指的是建立连接所需的最大时间。如果在这段时间内没有建立连接,连接将被放弃。
-
读取超时时间(Socket Timeout)
读取超时时间指的是从服务器读取数据的最大时间。如果在这段时间内没有读取到数据,读取操作将被放弃。
@Test
public void testTimeout() {
// 创建请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(10) // 连接超时时间
.setSocketTimeout(30) //读取超时时间
.build();
// 创建HttpClient实例并应用配置
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.build();
}
3.2 添加自定义请求头
通过HttpRequest
或其子类(如HttpGet
、HttpPost
等)的setHeader
方法来设置自定义请求头。
@Test
public void testCustomHeader(){
// 创建HttpClient实例
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建HttpGet请求
HttpGet getRequest = new HttpGet("http://example.com/api");
// 添加自定义请求头
getRequest.setHeader("Authorization", "Bearer your_token_here");
getRequest.setHeader("Custom-Header", "CustomValue");
}
3.3 使用连接池
在HttpClient中,连接池是用于管理HTTP连接的机制,它可以显著提高网络通信的性能和效率。HttpClient 4.x 版本使用 PoolingHttpClientConnectionManager
来实现连接池。
@Test
public void testClientPool(){
// 创建连接池管理器
try(PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager()){
connectionManager.setMaxTotal(200); // 设置最大连接数
connectionManager.setDefaultMaxPerRoute(20); // 设置每个路由的最大连接数
connectionManager.setValidateAfterInactivity(30);//设置连接在空闲多长时间后进行验证
// 创建请求配置
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时时间,单位:毫秒
.setSocketTimeout(10000) // 套接字超时时间(读取超时),单位:毫秒
.setConnectionRequestTimeout(3000) // 从连接池获取连接超时,单位:毫秒
.build();
// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.build();
// 使用httpClient执行请求
// ...
}
}
配置说明
setConnectTimeout(int timeout)
:设置连接超时时间,即连接建立的超时时间。超时时间到达之前如果无法建立连接,则会抛出SocketTimeoutException
。setSocketTimeout(int timeout)
:设置套接字超时时间,即数据读取的超时时间。超时时间到达之前如果没有接收到数据,则会抛出SocketTimeoutException
。setConnectionRequestTimeout(int timeout)
:设置从连接池获取连接的超时时间。如果超时时间到达之前无法从连接池获取连接,则会抛出ConnectionPoolTimeoutException
。setValidateAfterInactivity(long ms)
:设置连接在空闲多长时间后进行验证(检查连接是否仍然有效)。
3.4 请求重试策略
在 HttpClient 4.x 中,重试机制可以通过实现 HttpRequestRetryHandler
接口来进行定制。这个接口允许你定义重试逻辑,以决定在请求失败时是否以及如何进行重试。
-
实现
HttpRequestRetryHandler
接口public class CustomRetryHandler implements HttpRequestRetryHandler { @Override public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { if (executionCount >= 3) { // 超过最大重试次数,放弃重试 return false; } if (exception instanceof NoHttpResponseException) { // 对于没有响应的异常,进行重试 return true; } // 其他异常根据需求决定是否重试 return false; } }
-
将其配置到
HttpClient
中@Test public void testRetry(){ HttpRequestRetryHandler retryHandler = new CustomRetryHandler(); CloseableHttpClient httpClient = HttpClients.custom() .setRetryHandler(retryHandler) .build(); }
3.5 异步请求
Apache HttpClient 的异步请求是通过 HttpAsyncClient
实现的,允许你在发送请求后立即继续执行其他操作,而不是阻塞等待响应。这个特性对于需要高并发和低延迟的网络通信非常有用。
使用异步请求需要导入依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.4</version>
</dependency>
基本概念:
CloseableHttpAsyncClient
:异步客户端,提供了异步发送请求和接收响应的能力。HttpAsyncRequestProducer
:异步请求生成器,创建要发送的请求。HttpAsyncResponseConsumer
:异步响应消费者,处理接收到的响应。FutureCallback
:处理异步操作结果的回调接口。
@Test
public void testAsync() throws IOException {
CountDownLatch latch = new CountDownLatch(1); // 用于等待异步操作完成
// 创建异步HttpClient
try(CloseableHttpAsyncClient httpClient=HttpAsyncClients.createDefault()){
// 启动HttpClient
httpClient.start();
// 创建异步请求
HttpAsyncRequestProducer requestProducer = HttpAsyncMethods.createGet("http://www.example.com");
HttpAsyncResponseConsumer<HttpResponse> responseConsumer = new BasicAsyncResponseConsumer();
// 执行异步请求
httpClient.execute(requestProducer, responseConsumer, new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse response) {
// 处理响应
System.out.println("Response received: " + response.getStatusLine());
latch.countDown();//通知主线程异步操作完成
}
@Override
public void failed(Exception ex) {
// 处理请求失败
ex.printStackTrace();
latch.countDown();//通知主线程异步操作完成
}
@Override
public void cancelled() {
// 处理请求取消
System.out.println("Request was cancelled.");
latch.countDown();//通知主线程异步操作完成
}
});
latch.await();//等待异步操作完成
}catch (Exception e){
e.printStackTrace();
}
}
3.6 拦截器
Apache HttpClient 的 拦截器(Interceptors) 是一种强大的机制,允许你在 HTTP 请求/响应的处理链中插入自定义逻辑(例如日志记录、重试、认证等)。拦截器基于责任链模式,可以在请求发送前或响应返回后修改数据。
3.6.1 拦截器类型
HttpClient 提供了两种主要拦截器:
- 请求拦截器:在请求发送到服务器前执行(如添加公共请求头)。
- 响应拦截器:在收到服务器响应后执行(如日志记录或错误处理)。
3.6.2 快速入门
示例1:添加全局请求头
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.io.entity.EntityUtils;
public class HeaderInterceptorExample {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 并添加拦截器
try (CloseableHttpClient httpClient = HttpClients.custom()
.addRequestInterceptor((request, entity, context) -> {
// 为所有请求添加公共请求头
request.setHeader("User-Agent", "Apache HttpClient Demo");
request.setHeader("X-Custom-Header", "Hello");
})
.build()) {
// 2. 发送请求
HttpGet request = new HttpGet("https://httpbin.org/get");
try (CloseableHttpResponse response = httpClient.execute(request)) {
System.out.println(EntityUtils.toString(response.getEntity()));
}
}
}
}
示例2:记录请求和响应日志
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.io.entity.EntityUtils;
public class LoggingInterceptorExample {
public static void main(String[] args) throws Exception {
try (CloseableHttpClient httpClient = HttpClients.custom()
// 请求拦截器(记录请求信息)
.addRequestInterceptor((request, entity, context) -> {
System.out.println(">>> Request: " + request.getMethod() + " " + request.getRequestUri());
System.out.println(">>> Headers: " + Arrays.toString(request.getHeaders()));
})
// 响应拦截器(记录响应信息)
.addResponseInterceptor((response, entity, context) -> {
System.out.println("<<< Response: " + response.getCode());
System.out.println("<<< Headers: " + Arrays.toString(response.getHeaders()));
})
.build()) {
HttpGet request = new HttpGet("https://httpbin.org/get");
try (CloseableHttpResponse response = httpClient.execute(request)) {
System.out.println(EntityUtils.toString(response.getEntity()));
}
}
}
}
3.6.3 自定义拦截器
实现 HttpRequestInterceptor
/ HttpResponseInterceptor
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpRequestInterceptor;
import org.apache.hc.core5.http.protocol.HttpContext;
public class CustomRequestInterceptor implements HttpRequestInterceptor {
@Override
public void process(HttpRequest request, HttpContext context) {
request.setHeader("X-Auth-Token", "123456");
System.out.println("Custom Interceptor: Added Auth Token");
}
}
使用方式:
CloseableHttpClient httpClient = HttpClients.custom()
.addRequestInterceptor(new CustomRequestInterceptor())
.build();
这个是请求拦截器,如果要实现响应拦截器只需要实现HttpResponseInterceptor即可