一、整体使用广度
从行业实际应用来看,Spring 框架(含 Spring Boot)占据 Java 后端的半壁江山,因此与其深度集成的 RestTemplate(同步)和 WebClient(异步,Spring 5+)是最主流的选择;而非 Spring 项目(如传统 Java 项目、中间件)中,Apache HttpClient 凭借成熟稳定的特性成为首选。
具体使用占比(基于社区调研、招聘需求、开源项目统计):
| 工具 | 使用占比(估算) | 核心场景 |
|---|---|---|
| RestTemplate | 40%+ | Spring Boot 同步 HTTP 请求(最主流) |
| Apache HttpClient | 25%+ | 非 Spring 项目、复杂 HTTP 需求(连接池、SSL、认证) |
| WebClient(Spring 5+) | 20%+ | Spring Boot 异步 / 响应式编程(趋势) |
| Java 11+ HttpClient | 10%+ | Java 11+ 无依赖项目、轻量异步场景 |
| 其他(OkHttp、Retrofit) | 5% 以内 | 移动端 / Android 联动、特定框架集成 |
二、分场景详解
1. Spring 项目:RestTemplate(同步)/ WebClient(异步)
Spring Boot 是当前 Java 后端最流行的框架(占比超 60%),而 RestTemplate/WebClient 作为 Spring 内置的 HTTP 客户端,几乎是 Spring 项目的 "标配",核心原因:
- 零额外依赖:Spring 核心包自带,无需引入第三方库,开箱即用。
- 无缝集成:支持 Spring 依赖注入、AOP、消息转换器(自动 JSON/XML 序列化)、异常处理等生态特性。
- API 简洁:模板方法设计(如 getForObject、postForEntity),无需关注底层连接管理、资源释放,开发效率极高。
- 升级平滑:Spring 5+ 推出 WebClient(响应式编程,支持异步 / 非阻塞),完美适配微服务高并发场景,逐步替代 RestTemplate 成为新趋势。
2. 非 Spring 项目:Apache HttpClient ------ 成熟稳定的 "万能工具"
在传统 Java 项目、中间件(如 Dubbo、Elasticsearch 客户端)、非 Spring 微服务中,Apache HttpClient 是绝对的主流,核心原因:
- 功能全面:支持连接池、SSL 证书自定义、重试策略、代理、Digest Auth 等所有复杂 HTTP 场景,是 Java 生态中功能最完善的 HTTP 客户端。
- 稳定性强:迭代近 20 年(4.x 版本已稳定多年),经过海量生产环境验证,bug 少、兼容性好。
- 线程安全:CloseableHttpClient 实例可全局单例,连接池优化成熟,适合高并发场景。
- 生态兼容:很多框架(如 RestTemplate 可配置其作为底层请求工厂)、工具类都基于它封装,间接扩大了其使用范围。
3. 其他工具
- Java 11+ HttpClient:作为 Java 标准库,无需第三方依赖,但功能不如 Apache HttpClient 丰富(如连接池配置、重试策略需手动实现),仅在 Java 11+ 无依赖场景中使用较多。
- OkHttp:由 Square 开发,API 简洁、支持 HTTP/2,在 Android 端使用广泛,但 Java 后端项目中因缺乏框架深度集成,使用占比远低于前三者。
- Retrofit:基于 OkHttp 封装的声明式 HTTP 客户端(类似 Spring Cloud OpenFeign),适合 API 接口较多的场景,但需额外定义接口,灵活性略低,主要用于特定业务场景。
三、RestTemplate 详解
RestTemplate 是 Spring 3.0 提供的 HTTP 客户端工具,封装了底层 HTTP 通信细节(默认使用 HttpURLConnection,可替换为 HttpClient/OkHttp),支持 Spring 生态的特性(如依赖注入、异常处理、消息转换器),适合 Spring 项目使用。
1. 核心组件与参数
(1)RestTemplate 初始化
通过 RestTemplateBuilder 或直接 new 初始化,核心配置参数如下:
| 参数 | 说明 | 示例代码 |
|---|---|---|
| setConnectTimeout | 连接超时(毫秒) | .setConnectTimeout(Duration.ofSeconds(5)) |
| setReadTimeout | 读取超时(等待响应数据的时间,毫秒) | .setReadTimeout(Duration.ofSeconds(10)) |
| setDefaultHeader | 默认请求头(所有请求共享) | .setDefaultHeader("User-Agent", "RestTemplate/Spring") |
| messageConverters | 消息转换器(将请求体转为 JSON/XML,响应体转为 Java 对象) | .messageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())) |
| requestFactory | 底层 HTTP 工厂(默认 SimpleClientHttpRequestFactory,可替换为 HttpComponentsClientHttpRequestFactory 以支持 HttpClient 特性) | .requestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)) |
| errorHandler | 错误处理器(自定义 4xx/5xx 响应的异常处理) | .errorHandler(new DefaultResponseErrorHandler() { ... }) |
| interceptors | 请求拦截器(统一添加头信息、日志打印、认证等) | .interceptors(new LoggingInterceptor()) |
(2)核心请求方法
RestTemplate 提供了丰富的模板方法,无需手动构建请求体 / 响应体,核心方法如下:
| 方法名 | 说明 | 适用场景 |
|---|---|---|
| getForObject() | GET 请求,直接返回响应体转为的 Java 对象 | 响应体为 JSON/XML,需映射为实体类 |
| getForEntity() | GET 请求,返回 ResponseEntity(含状态码、头、响应体) | 需获取响应头 / 状态码 |
| postForObject() | POST 请求,返回响应体对象 | 提交数据并获取结果 |
| postForEntity() | POST 请求,返回 ResponseEntity | 需获取响应元数据 |
| postForLocation() | POST 请求,返回重定向地址(Location 头) | 表单提交后重定向 |
| put() | PUT 请求(无返回值) | 更新资源 |
| delete() | DELETE 请求(无返回值) | 删除资源 |
| exchange() | 通用方法(支持自定义请求方法、头、请求体) | 复杂场景(如 PATCH、自定义头) |
| execute() | 最底层方法(完全自定义请求 / 响应处理) | 特殊需求(如二进制流处理) |
(3)关键参数说明
- URL 参数占位符:支持 {name} 占位符,自动替换参数(避免字符串拼接错误):
java
// 方式1:直接拼接参数
restTemplate.getForObject("https://api.example.com/user/{id}", User.class, 1001);
// 方式2:Map 传递参数
Map<String, Object> params = new HashMap<>();
params.put("id", 1001);
restTemplate.getForObject("https://api.example.com/user/{id}", User.class, params);
- 请求头(HttpHeaders):通过 HttpEntity 封装请求头和请求体:
java
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/json");
headers.set("Authorization", "Bearer your-token");
HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers); // 请求体+头
2. RestTemplate 完整示例
- Spring Boot 中初始化 RestTemplate(推荐)
在 Spring Boot 项目中,通过 @Bean 注入 RestTemplate,统一配置:
- 简单配置示例:
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Collections;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
// 1. 配置底层 HTTP 工厂
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(Duration.ofSeconds(5));
factory.setReadTimeout(Duration.ofSeconds(10));
factory.setConnectionRequestTimeout(Duration.ofSeconds(3));
// 2. 构建 RestTemplate(指定工厂)
RestTemplate restTemplate = new RestTemplate(factory);
// 3. 移除默认的 StringHttpMessageConverter(避免其默认 ISO-8859-1 编码冲突)
restTemplate.getMessageConverters().removeIf(converter -> converter instanceof StringHttpMessageConverter);
// 4. 配置 JSON 转换器(明确指定 UTF-8 字符集)
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
jsonConverter.setDefaultCharset(StandardCharsets.UTF_8); // 核心:设置 UTF-8
restTemplate.getMessageConverters().add(jsonConverter);
// 5. (可选)如果需要单独处理 String 响应,添加 UTF-8 编码的 String 转换器
restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
// 6. 请求拦截器(保持不变)
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
request.getHeaders().set("Authorization", "Bearer your-token");
// 可选:给请求头添加 Content-Type(明确告知服务端请求体是 UTF-8 编码的 JSON)
request.getHeaders().setContentType(org.springframework.http.MediaType.APPLICATION_JSON_UTF8);
return execution.execute(request, body);
}));
return restTemplate;
}
}
- 高级配置示例(含连接池、HTTPS、重试):
依赖引入(Maven):
xml
<!-- Apache HttpClient 核心依赖 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version> <!-- 适配 Spring 版本,避免冲突 -->
</dependency>
java
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.time.Duration;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
// 1. 配置 HttpClient 连接池
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200); // 连接池最大总连接数
connectionManager.setDefaultMaxPerRoute(50); // 每个路由(域名)的最大连接数
connectionManager.setValidateAfterInactivity(30000); // 空闲连接校验时间(30s)
// 2. 配置 HTTPS(跳过证书校验,生产环境建议用真实证书)
SSLContext sslContext = null;
try {
sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, (certificate, authType) -> true) // 信任所有证书
.build();
} catch (Exception e) {
throw new RuntimeException("HTTPS 配置失败", e);
}
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE); // 禁用主机名校验
// 3. 配置请求超时
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时 5s
.setSocketTimeout(10000) // 读取超时 10s
.setConnectionRequestTimeout(3000) // 从连接池获取连接的超时 3s
.build();
// 4. 构建 HttpClient 实例
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.setSSLSocketFactory(sslSocketFactory)
.evictIdleConnections(Duration.ofSeconds(60)) // 60s 空闲连接自动关闭
.build();
// 5. 包装为 Spring 的请求工厂
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
// 6. 构建 RestTemplate
return new RestTemplate(factory);
}
}
- GET 请求(返回实体类、带参数)
java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
// 1. 配置底层 HTTP 工厂(使用 HttpClient 提升性能,支持连接池)
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(Duration.ofSeconds(5)); // 连接超时
factory.setReadTimeout(Duration.ofSeconds(10)); // 读取超时
factory.setConnectionRequestTimeout(Duration.ofSeconds(3)); // 从连接池获取连接的超时
// 2. 构建 RestTemplate
RestTemplate restTemplate = new RestTemplate(factory);
// 3. 添加 JSON 消息转换器(支持请求体/响应体自动转换)
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// 4. 添加请求拦截器(示例:统一添加 Authorization 头)
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
request.getHeaders().set("Authorization", "Bearer your-token");
return execution.execute(request, body);
}));
return restTemplate;
}
}
- POST 请求(JSON 体、Basic Auth)
java
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Base64;
public class RestTemplatePostExample {
@Resource
private RestTemplate restTemplate;
public String login() {
// 1. 构建 JSON 请求体(也可直接传入 User 对象,RestTemplate 自动转为 JSON)
UserLoginRequest loginRequest = new UserLoginRequest("test", "123456");
// 2. 配置请求头(Basic Auth + JSON 格式)
String username = "admin";
String password = "123456";
String auth = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); // JSON 格式
headers.set("Authorization", auth);
// 3. 封装请求实体(请求体 + 头)
HttpEntity<UserLoginRequest> requestEntity = new HttpEntity<>(loginRequest, headers);
// 4. 发送 POST 请求(返回响应体字符串)
String response = restTemplate.postForObject(
"https://api.example.com/login",
requestEntity,
String.class
);
// 5. 若返回 JSON,直接转为实体类
LoginResponse loginResponse = restTemplate.postForObject(
"https://api.example.com/login",
requestEntity,
LoginResponse.class
);
return loginResponse.getToken();
}
// 请求实体类
static class UserLoginRequest {
private String username;
private String password;
// 构造器/getter/setter
}
// 响应实体类
static class LoginResponse {
private String token;
private Long expireTime;
// getter/setter
}
}
四、Apache HttpClient 详解
Apache HttpClient(org.apache.httpcomponents)是 Java 生态中最成熟、功能最强大的 HTTP 客户端工具之一,相比 Java 11 内置的 HttpClient 和 Spring 的 RestTemplate,它提供了更精细的配置选项(如连接池、SSL 证书、重试策略等)
1.核心依赖
首先需要在项目中引入 Apache HttpClient 的 Maven/Gradle 依赖:
Maven 依赖
xml
<!-- 核心依赖(HTTP 客户端基础功能) -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version> <!-- 最新稳定版 -->
</dependency>
<!-- 可选:支持 Multipart 表单(文件上传) -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.14</version>
</dependency>
<!-- 可选:JSON 序列化(与 Jackson 配合) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.3</version>
</dependency>
2.核心组件与关键参数
Apache HttpClient 的核心是 CloseableHttpClient(客户端实例),通过 HttpClientBuilder 构建,配合 HttpGet/HttpPost 等请求对象、HttpEntity(请求体 / 响应体)完成 HTTP 通信。
- 核心组件说明
| 组件类名 | 作用 |
|---|---|
| HttpClientBuilder | 构建 CloseableHttpClient 的核心构建器,配置全局参数(连接池、超时、SSL 等) |
| CloseableHttpClient | HTTP 客户端实例,负责发送请求、接收响应(线程安全,建议全局单例) |
| HttpGet/HttpPost/HttpPut/HttpDelete | 具体的 HTTP 请求对象,配置请求 URL、头、参数等 |
| HttpEntity | 封装请求体 / 响应体数据(如字符串、字节流、文件等),需手动关闭资源 |
| HttpResponse | HTTP 响应对象,包含状态码、响应头、响应体(HttpEntity) |
| RequestConfig | 单个请求的配置(超时、重定向策略等,可覆盖全局配置) |
| PoolingHttpClientConnectionManager | 连接池管理器,控制最大连接数、每个路由连接数等(性能优化核心) |
- 关键配置参数
(1)全局配置(HttpClientBuilder)
通过 HttpClientBuilder 配置客户端级别的全局参数,核心参数如下:
| 参数方法 | 说明 | 示例代码 |
|---|---|---|
| setConnectionManager | 设置连接池管理器(必配,优化性能) | .setConnectionManager(connectionManager) |
| setDefaultRequestConfig | 设置默认请求配置(超时、重定向等) | .setDefaultRequestConfig(defaultRequestConfig) |
| setSSLContext | 配置 SSL 上下文(自定义证书、跳过 SSL 验证) | .setSSLContext(sslContext) |
| setSSLSocketFactory | SSL 套接字工厂(配合 SSLContext 配置加密套件、协议版本) | .setSSLSocketFactory(sslSocketFactory) |
| setProxy | 配置代理(HTTP/HTTPS 代理) | .setProxy(new HttpHost("127.0.0.1", 8888)) |
| setDefaultCredentialsProvider | 默认凭证提供器(Basic Auth、Digest Auth 等全局认证) | .setDefaultCredentialsProvider(credentialsProvider) |
| setRetryHandler | 重试策略(网络异常、5xx 状态码自动重试) | .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) |
| setUserAgent | 默认 User-Agent 头 | .setUserAgent("Apache-HttpClient/4.5.14") |
| disableAutomaticRetries | 禁用自动重试 | .disableAutomaticRetries() |
| setMaxConnTotal | 最大总连接数(连接池全局限制,替代连接池管理器的配置) | .setMaxConnTotal(200) |
| setMaxConnPerRoute | 每个路由最大连接数(单个域名 / IP 的连接限制) | .setMaxConnPerRoute(50) |
(2)请求级配置(RequestConfig)
通过 RequestConfig.Builder 配置单个请求的参数,可覆盖全局配置:
| 参数方法 | 说明 | 示例代码 |
|---|---|---|
| setConnectTimeout | 连接超时(建立 TCP 连接的时间限制,毫秒) | .setConnectTimeout(5000)(5 秒) |
| setSocketTimeout | 读取超时(等待响应数据的时间限制,毫秒) | .setSocketTimeout(10000)(10 秒) |
| setConnectionRequestTimeout | 从连接池获取连接的超时时间(毫秒) | .setConnectionRequestTimeout(3000)(3 秒) |
| setRedirectsEnabled | 是否允许重定向(默认 true) | .setRedirectsEnabled(false) |
| setMaxRedirects | 最大重定向次数 | .setMaxRedirects(3) |
| setCircularRedirectsAllowed | 是否允许循环重定向(默认 false) | .setCircularRedirectsAllowed(true) |
(3)连接池配置(PoolingHttpClientConnectionManager)
连接池是高并发场景的核心优化,通过 PoolingHttpClientConnectionManager 配置:
| 参数方法 | 说明 | 示例代码 |
|---|---|---|
| setMaxTotal | 连接池最大总连接数(默认 20) | .setMaxTotal(200) |
| setDefaultMaxPerRoute | 每个路由默认最大连接数(默认 2) | .setDefaultMaxPerRoute(50) |
| setMaxPerRoute | 为特定路由设置最大连接数(如对某个域名单独限制) | .setMaxPerRoute(new HttpRoute(httpHost), 100) |
| setConnectionTimeToLive | 连接存活时间(超过时间自动关闭,避免空闲连接占用资源) | .setConnectionTimeToLive(30, TimeUnit.SECONDS) |
| closeExpiredConnections | 关闭过期的连接(建议定时调用,如定时任务每 30 秒执行一次) | connectionManager.closeExpiredConnections() |
| closeIdleConnections | 关闭空闲超过指定时间的连接 | connectionManager.closeIdleConnections(60, TimeUnit.SECONDS) |
3. HttpClient 完整示例
1. 基础配置:创建全局 HttpClient 实例(单例)
建议在项目中使用单例模式创建 CloseableHttpClient,避免重复创建销毁连接池:
java
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeUnit;
public class HttpClientConfig {
// 单例 HttpClient 实例
private static CloseableHttpClient httpClient;
static {
try {
httpClient = createHttpClient();
} catch (Exception e) {
throw new RuntimeException("创建 HttpClient 失败", e);
}
}
public static CloseableHttpClient getHttpClient() {
return httpClient;
}
private static CloseableHttpClient createHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
// 1. 配置 SSL 上下文(默认使用系统信任证书,生产环境建议自定义)
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, (chain, authType) -> true) // 跳过 SSL 验证(仅测试环境)
.build();
// 2. 创建连接池管理器
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
HttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
// 3. 配置连接池参数
PoolingHttpClientConnectionManager poolingManager = (PoolingHttpClientConnectionManager) connectionManager;
poolingManager.setMaxTotal(200); // 最大总连接数
poolingManager.setDefaultMaxPerRoute(50); // 每个路由默认最大连接数
// 为特定路由设置更大的连接数(如 API 服务器)
HttpHost apiHost = new HttpHost("api.example.com", 443, "https");
poolingManager.setMaxPerRoute(new HttpRoute(apiHost), 100);
// 4. 配置默认请求参数(超时、重定向等)
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时 5 秒
.setSocketTimeout(10000) // 读取超时 10 秒
.setConnectionRequestTimeout(3000) // 连接池获取连接超时 3 秒
.setRedirectsEnabled(true) // 允许重定向
.setMaxRedirects(3) // 最大重定向 3 次
.build();
// 5. 构建 HttpClient
return HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(defaultRequestConfig)
.setUserAgent("Apache-HttpClient/4.5.14")
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // 重试 3 次(非幂等请求不重试)
.build();
}
// 定时清理过期/空闲连接(建议在项目启动时启动定时任务)
public static void startConnectionCleanupTask() {
HttpClientConnectionManager connectionManager = ((PoolingHttpClientConnectionManager) httpClient.getConnectionManager());
new Thread(() -> {
while (true) {
try {
Thread.sleep(30000); // 每 30 秒执行一次
connectionManager.closeExpiredConnections(); // 关闭过期连接
connectionManager.closeIdleConnections(60, TimeUnit.SECONDS); // 关闭空闲 60 秒以上的连接
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
}
}
2. GET 请求(带查询参数、请求头)
java
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
public class HttpClientGetExample {
public static void main(String[] args) {
CloseableHttpClient httpClient = HttpClientConfig.getHttpClient();
CloseableHttpResponse response = null;
try {
// 1. 构建 GET 请求 URL(带查询参数)
String baseUrl = "https://api.example.com/user";
Map<String, String> params = new HashMap<>();
params.put("id", "1001");
params.put("name", "test");
// 使用 URIBuilder 拼接参数(自动处理 URL 编码)
URIBuilder uriBuilder = new URIBuilder(baseUrl);
for (Map.Entry<String, String> entry : params.entrySet()) {
uriBuilder.addParameter(entry.getKey(), entry.getValue());
}
URI uri = uriBuilder.build();
// 2. 创建 HttpGet 请求对象
HttpGet httpGet = new HttpGet(uri);
// 3. 设置请求头
httpGet.setHeader("Authorization", "Bearer your-token");
httpGet.setHeader("User-Agent", "Apache-HttpClient/Test");
httpGet.setHeader("Accept", "application/json");
// 4. (可选)覆盖全局请求配置(如单独设置超时)
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(15000) // 读取超时 15 秒(覆盖全局 10 秒)
.build();
httpGet.setConfig(requestConfig);
// 5. 发送请求并获取响应
response = httpClient.execute(httpGet);
// 6. 处理响应
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("状态码:" + statusCode);
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String responseBody = EntityUtils.toString(responseEntity, "UTF-8"); // 响应体转为字符串(指定 UTF-8)
System.out.println("响应体:" + responseBody);
// 若响应为 JSON,可转为 Java 对象(配合 Jackson)
// ObjectMapper objectMapper = new ObjectMapper();
// User user = objectMapper.readValue(responseBody, User.class);
}
// 7. 消耗响应体(避免连接泄漏)
EntityUtils.consume(responseEntity);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 8. 关闭响应对象(必须关闭,释放连接)
if (response != null) {
try {
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 实体类示例
static class User {
private Long id;
private String name;
// getter/setter/toString
}
}
3. POST 请求(JSON 体、Basic Auth)
java
import org.apache.http.HttpEntity;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
public class HttpClientPostExample {
public static void main(String[] args) {
CloseableHttpClient httpClient = HttpClientConfig.getHttpClient();
CloseableHttpResponse response = null;
ObjectMapper objectMapper = new ObjectMapper(); // Jackson JSON 工具
try {
// 1. 配置 Basic Auth(两种方式:全局凭证/请求头)
// 方式1:全局凭证(通过 HttpClientBuilder 配置,适用于所有请求)
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY, // 对所有地址生效
new UsernamePasswordCredentials("admin", "123456")
);
// 若需单独为该请求配置 Auth,可创建新的 HttpClient:
// CloseableHttpClient authHttpClient = HttpClientBuilder.create().setDefaultCredentialsProvider(credentialsProvider).build();
// 方式2:手动添加 Basic Auth 头(更灵活)
String auth = "Basic " + java.util.Base64.getEncoder().encodeToString(("admin:123456").getBytes());
// 2. 创建 HttpPost 请求对象
HttpPost httpPost = new HttpPost("https://api.example.com/login");
// 3. 设置请求头
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setHeader("Authorization", auth); // Basic Auth 头
// 4. 构建 JSON 请求体(两种方式:字符串/Java 对象)
// 方式1:直接传入 JSON 字符串
String jsonBody = "{\"username\":\"test\",\"password\":\"123456\"}";
// 方式2:Java 对象转为 JSON 字符串(推荐,避免手动拼接错误)
LoginRequest loginRequest = new LoginRequest("test", "123456");
jsonBody = objectMapper.writeValueAsString(loginRequest);
// 5. 设置请求体(StringEntity 封装字符串,指定编码)
StringEntity requestEntity = new StringEntity(jsonBody, "UTF-8");
httpPost.setEntity(requestEntity);
// 6. 发送请求
response = httpClient.execute(httpPost);
// 7. 处理响应
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("状态码:" + statusCode);
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String responseBody = EntityUtils.toString(responseEntity, "UTF-8");
System.out.println("响应体:" + responseBody);
// JSON 响应转为 Java 对象
LoginResponse loginResponse = objectMapper.readValue(responseBody, LoginResponse.class);
System.out.println("登录令牌:" + loginResponse.getToken());
}
EntityUtils.consume(responseEntity);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
try {
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 请求实体类
static class LoginRequest {
private String username;
private String password;
public LoginRequest(String username, String password) {
this.username = username;
this.password = password;
}
// getter/setter
}
// 响应实体类
static class LoginResponse {
private String token;
private Long expireTime;
// getter/setter
}
}