RestTemplate 和 Apache HttpClient 实现 HTTP 请求

一、整体使用广度

从行业实际应用来看,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 完整示例

  1. 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);
    }
}
  1. 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;
    }
}
  1. 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
    }
}
相关推荐
qq_356531453 小时前
浏览器访问web服务器经过了哪些过程
网络协议
浔川python社4 小时前
《Python 小程序编写系列》(第三部):简易文件批量重命名工具
python·小程序·apache
それども4 小时前
HTTP接口和Dubbo接口区别
网络协议·http·dubbo
铭哥的编程日记4 小时前
【Linux网络】应用层协议HTTP
linux·运维·http
SelectDB4 小时前
替换 ClickHouse,查询并发提升 7 倍!高途教育基于阿里云 SelectDB 构建秒级实时报表
数据库·apache
诚实可靠王大锤5 小时前
WebSocket调试工具(html),用于调试WebSocket链接是否畅通
websocket·网络协议·html
Moonbit5 小时前
MoonBit Pearls Vol.13: 使用 MoonBit 开发一个 HTTP 文件服务器
服务器·后端·http
一雨方知深秋6 小时前
AJAX学习 ---- axios体验
javascript·http·ajax·axios·url·catch·then
24zhgjx-fuhao7 小时前
HTTP的配置
网络·网络协议·http