目录
- 为什么选择 HttpClient? (与其他方案如
HttpURLConnection的对比) - 环境搭建 (Maven/Gradle 依赖)
- 核心组件简介
- 实战演练
- 示例 1: 发送一个简单的 GET 请求
- 示例 2: 发送一个 POST 请求 (发送 JSON 数据)
- 示例 3: 发送一个 POST 请求 (发送表单数据)
- 示例 4: 处理响应和错误
- 高级特性
- 连接池
- 异步请求
- 超时设置
- 最佳实践与总结
为什么选择 HttpClient?
相比于 Java 原生的 HttpURLConnection,Apache HttpClient 有以下优势:

- API 更强大、更灵活:提供了更丰富的 API,可以轻松处理各种 HTTP 请求、响应、头部、Cookie 等。
- 功能更全面:内置了连接池、重试机制、压缩支持、身份验证等高级功能,无需自己实现。
- 性能更好:通过连接池可以高效地复用 TCP 连接,避免了频繁创建和销毁连接的开销。
- 社区活跃,维护良好:由 Apache 软件基金会维护,是目前事实上的 Java HTTP 客户端标准之一。
环境搭建
你需要在你的项目中添加 HttpClient 的依赖。
使用 Maven
在你的 pom.xml 文件中添加以下依赖:
<dependencies>
<!-- Apache HttpClient 核心库 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version> <!-- 请使用最新版本 -->
</dependency>
<!-- 为了支持 JSON,我们通常需要一个 JSON 库,如 Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> <!-- 请使用最新版本 -->
</dependency>
</dependencies>
使用 Gradle
在你的 build.gradle 文件中添加以下依赖:
dependencies {
// Apache HttpClient 核心库
implementation 'org.apache.httpcomponents.client5:httpclient5:5.3.1' // 请使用最新版本
// 为了支持 JSON,我们通常需要一个 JSON 库,如 Jackson
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2' // 请使用最新版本
}
核心组件简介
在开始编码前,了解几个核心组件很重要:

CloseableHttpClient: 执行 HTTP 请求的主要入口点,它是一个客户端对象,负责管理连接和执行请求,使用后需要关闭。HttpUriRequest: 表示一个 HTTP 请求的接口,常用的实现类有HttpGet,HttpPost,HttpPut,HttpDelete等。HttpResponse: 表示从服务器收到的 HTTP 响应,它包含状态码、响应头和响应体。EntityUtils: 一个工具类,用于从HttpEntity(响应体) 中读取内容并转换为字符串或字节数组。
实战演练
示例 1: 发送一个简单的 GET 请求
这个例子会向 httpbin.org/get 发送一个 GET 请求,并打印响应内容。
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;
import org.apache.hc.core5.http.ParseException;
public class SimpleGetRequest {
public static void main(String[] args) {
// 1. 创建 HttpClient 实例
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 2. 创建 HttpGet 请求
HttpGet request = new HttpGet("https://httpbin.org/get?name=test&age=30");
// 3. 执行请求,获取响应
try (CloseableHttpResponse response = httpClient.execute(request)) {
// 4. 检查响应状态码
System.out.println("Response Code: " + response.getCode());
// 5. 获取响应实体
String responseBody = EntityUtils.toString(response.getEntity());
// 6. 打印响应内容
System.out.println("Response Body:");
System.out.println(responseBody);
} catch (ParseException | IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键点:
- 使用
try-with-resources语句 (try (CloseableHttpClient ...)和try (CloseableHttpResponse ...)) 来确保HttpClient和HttpResponse在使用后被正确关闭,防止资源泄漏。 EntityUtils.toString(response.getEntity())将响应体(通常是字节流)转换为字符串。
示例 2: 发送一个 POST 请求 (发送 JSON 数据)
这个例子会向 httpbin.org/post 发送一个 POST 请求,请求体是 JSON 格式。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hc.client5.http.classic.methods.HttpPost;
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.HttpEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.ParseException;
public class PostJsonRequest {
public static void main(String[] args) {
// 1. 创建 HttpClient 实例
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 2. 创建 HttpPost 请求
HttpPost postRequest = new HttpPost("https://httpbin.org/post");
// 3. 准备 JSON 数据
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("Alice", 25);
String jsonBody = objectMapper.writeValueAsString(user);
// 4. 设置请求体和内容类型
StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
postRequest.setEntity(entity);
// 5. 执行请求
try (CloseableHttpResponse response = httpClient.execute(postRequest)) {
System.out.println("Response Code: " + response.getCode());
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Response Body:");
System.out.println(responseBody);
} catch (ParseException | IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 用于 JSON 序列化的简单 POJO
static class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Getters and Setters (省略,实际项目中需要)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
}
关键点:

HttpPost用于创建 POST 请求。StringEntity用于将字符串(如 JSON)包装成一个 HTTP 实体。ContentType.APPLICATION_JSON明确告诉服务器我们发送的是 JSON 数据。- 使用 Jackson 的
ObjectMapper将 Java 对象轻松转换为 JSON 字符串。
示例 3: 发送一个 POST 请求 (发送表单数据)
这个例子演示如何向 httpbin.org/post 发送 application/x-www-form-urlencoded 格式的表单数据。
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
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.HttpEntity;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URIBuilder;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
public class PostFormRequest {
public static void main(String[] args) throws URISyntaxException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// 1. 创建 HttpPost 请求,并可以构建带查询参数的 URL
URI uri = new URIBuilder("https://httpbin.org/post")
.addParameter("param1", "value1")
.build();
HttpPost postRequest = new HttpPost(uri);
// 2. 准备表单数据
List<BasicNameValuePair> formParams = new ArrayList<>();
formParams.add(new BasicNameValuePair("username", "john.doe"));
formParams.add(new BasicNameValuePair("password", "secret123"));
// 3. 设置请求体
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formParams);
postRequest.setEntity(formEntity);
// 4. 执行请求
try (CloseableHttpResponse response = httpClient.execute(postRequest)) {
System.out.println("Response Code: " + response.getCode());
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Response Body:");
System.out.println(responseBody);
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键点:
UrlEncodedFormEntity用于创建表单实体。BasicNameValuePair表示一个键值对。URIBuilder是一个方便的工具,用于构建复杂的 URL,包括查询参数。
示例 4: 处理响应和错误
处理 HTTP 响应时,状态码非常重要。
// ... (创建 HttpClient 和 Request 的代码相同)
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getCode();
if (statusCode >= 200 && statusCode < 300) {
// 请求成功
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("Success: " + responseBody);
} else {
// 请求失败
System.err.println("Request failed with status code: " + statusCode);
// 可以读取错误响应体
String errorBody = EntityUtils.toString(response.getEntity());
System.err.println("Error Body: " + errorBody);
}
} // ...
高级特性
连接池
在高并发场景下,为每个请求都创建一个 HttpClient 是非常低效的,连接池可以复用 TCP 连接,显著提升性能。
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.pool.PoolStats;
import org.apache.hc.core5.reactor.ConnectingIOReactor;
import org.apache.hc.core5.reactor.ConnectingIOReactorFactory;
import org.apache.hc.core5.reactor.IOReactorConfig;
// 创建带连接池的 HttpClient
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// 设置最大连接数
cm.setMaxTotal(100);
// 设置每个路由(目标主机)的最大连接数
cm.setDefaultMaxPerRoute(20);
// 创建 HttpClient
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
// 使用 httpClient ...
// 使用完后关闭
httpClient.close();
// 注意:连接池本身也会被关闭
异步请求
HttpClient 5.x 提供了强大的异步非阻塞 API,基于 Java NIO 和 CompletableFuture。
import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
public class AsyncRequestExample {
public static void main(String[] args) throws Exception {
// 1. 创建异步客户端
try (CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault()) {
// 2. 启动客户端
httpClient.start();
// 3. 创建异步请求
SimpleHttpRequest request = SimpleRequestBuilder.get("https://httpbin.org/get")
.addParameter("name", "async")
.build();
// 4. 执行异步请求,并提供回调
httpClient.execute(request, new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(SimpleHttpResponse response) {
System.out.println("Async Response Code: " + response.getCode());
System.out.println("Async Response Body: " + response.getBodyText());
}
@Override
public void failed(Exception ex) {
System.err.println("Async request failed: " + ex.getMessage());
}
@Override
public void cancelled() {
System.err.println("Async request was cancelled.");
}
});
// 5. 为了让主线程等待异步任务完成,可以睡一会儿
// 在实际应用中,主线程通常有自己的事件循环
System.out.println("Request sent. Waiting for response...");
Thread.sleep(5000); // 等待5秒
}
}
}
超时设置
为了避免因网络问题或服务器无响应而无限期等待,设置超时非常重要。
import org.apache.hc.client5.http.config.RequestConfig;
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.config.ConnectionRequestConfig;
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时 (毫秒)
.setConnectionRequestTimeout(3000) // 从连接池获取连接的超时
.setResponseTimeout(10000) // 等待响应的超时
.build();
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(requestConfig)
.build();
最佳实践与总结
- 总是使用
try-with-resources:确保CloseableHttpClient和CloseableHttpResponse被正确关闭,防止资源泄漏。 - 重用
HttpClient实例:不要为每个请求都创建一个新的HttpClient,它应该是线程安全的,可以在整个应用生命周期内被重用。 - 使用连接池:对于任何生产环境或高并发场景,务必使用连接池来提升性能。
- 设置合理的超时:为连接、请求和响应设置合理的超时时间,使你的应用更加健壮。
- 处理响应状态码:不要只假设请求会成功,检查响应状态码并处理可能的错误。
- 考虑使用更高级的封装:对于复杂的业务逻辑,可以考虑基于 HttpClient 封装一个更简洁、更符合你项目风格的客户端工具类。
希望这份详细的指南能帮助你掌握在 Java 中使用 HttpClient 进行 HTTP 调用!
