SpringBoot19-HttpClient 详解及 SpringBoot 使用指南
一、HttpClient 是什么?
HttpClient 是 Apache 提供的一个 HTTP 协议客户端工具库,用于在 Java 应用中发送 HTTP 请求和接收 HTTP 响应。它比 Java 原生的
HttpURLConnection更加强大和易用。
主要特性:
- 支持多种 HTTP 方法:GET、POST、PUT、DELETE 等
- 连接池管理:复用连接,提高性能
- 超时控制:连接超时、读取超时
- 重试机制:自动重试失败的请求
- Cookie 管理:自动处理 Cookie
- SSL/TLS 支持:支持 HTTPS
- 请求/响应拦截器:可以自定义处理逻辑
二、在 SpringBoot 中使用 HttpClient
1. 添加依赖
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.14</version>
</dependency>
【备注】:
若是加了阿里云oss的依赖,可以不加httpclient的依赖,因为阿里云oss的依赖中已经包含了httpclient的依赖。
2、测试使用示例
package com.sky.test;import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import io.swagger.util.Json;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;
import java.io.UnsupportedEncodingException;@SpringBootTest
public class HttpClientTest {@Testpublic void testGet() throws IOException {// 创建httpClient对象CloseableHttpClient httpClient = HttpClients.createDefault();// 创建请求对象HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");// 发送请求,接收响应信息CloseableHttpResponse httpResponse = httpClient.execute(httpGet);// 获取服务端返回的状态码int statusCode = httpResponse.getStatusLine().getStatusCode();System.out.println("服务端返回的状态码为: " + statusCode);HttpEntity httpEntity = httpResponse.getEntity();String body = EntityUtils.toString(httpEntity);System.out.println("服务端返回的数据为:" + body);// 关闭资源httpResponse.close();httpClient.close();}@Testpublic void testPost() throws Exception {// 创建 httpClient 对象CloseableHttpClient httpClient = HttpClients.createDefault();// 创建post请求对象HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");// 以json的方式提交请求参数JSONObject jsonObject = new JSONObject();jsonObject.put("username", "admin");jsonObject.put("password", "123456");StringEntity stringEntity = new StringEntity(jsonObject.toString());// 指定请求的编码方式stringEntity.setContentEncoding("utf-8");// 指定数据格式stringEntity.setContentType("application/json");httpPost.setEntity(stringEntity);// 发送请求CloseableHttpResponse httpResponse = httpClient.execute(httpPost);// 获得响应码int statusCode = httpResponse.getStatusLine().getStatusCode();System.out.println("服务区返回的响应码:" + statusCode);HttpEntity responseEntity = httpResponse.getEntity();String body = EntityUtils.toString(responseEntity);System.out.println("服务端返回的响应体:{}" + body);// 关闭资源httpResponse.close();httpClient.close();}}
3. 配置 HttpClient(推荐方式)
创建一个配置类,将 HttpClient 注册为 Spring Bean:
@Configuration
public class HttpClientConfig {@Beanpublic HttpClient httpClient() {// 连接池管理PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();connectionManager.setMaxTotal(200); // 最大连接数connectionManager.setDefaultMaxPerRoute(20); // 每个路由最大连接数// 请求配置RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000) // 连接超时 5 秒.setSocketTimeout(10000) // 读取超时 10 秒.setConnectionRequestTimeout(3000) // 从连接池获取连接超时 3 秒.build();// 构建 HttpClientreturn HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) // 重试 3 次.build();}@Beanpublic CloseableHttpClient closeableHttpClient() {return HttpClients.createDefault();}
}
为什么?
HttpClient是 Apache 提供的第三方类- 它不在 Spring 的扫描路径下
- 没有
@Component、@Service等注解- Spring 容器根本不知道它的存在
所以需要配置类手动注册。
4. 使用示例
GET 请求:
@Service
public class HttpClientService {@Autowiredprivate HttpClient httpClient;public String doGet(String url) throws IOException {HttpGet httpGet = new HttpGet(url);// 设置请求头httpGet.setHeader("User-Agent", "Mozilla/5.0");httpGet.setHeader("Accept", "application/json");HttpResponse response = httpClient.execute(httpGet);// 获取响应状态码int statusCode = response.getStatusLine().getStatusCode();// 获取响应内容HttpEntity entity = response.getEntity();String result = EntityUtils.toString(entity, "UTF-8");// 释放资源EntityUtils.consume(entity);return result;}
}
POST 请求(JSON 数据):
public String doPostJson(String url, String jsonData) throws IOException {HttpPost httpPost = new HttpPost(url);// 设置请求头httpPost.setHeader("Content-Type", "application/json");// 设置请求体StringEntity stringEntity = new StringEntity(jsonData, "UTF-8");httpPost.setEntity(stringEntity);HttpResponse response = httpClient.execute(httpPost);String result = EntityUtils.toString(response.getEntity(), "UTF-8");EntityUtils.consume(response.getEntity());return result;
}
POST 请求(表单数据):
public String doPostForm(String url, Map<String, String> params) throws IOException {HttpPost httpPost = new HttpPost(url);// 构建表单参数List<NameValuePair> formParams = new ArrayList<>();for (Map.Entry<String, String> entry : params.entrySet()) {formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));}// 设置表单实体UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");httpPost.setEntity(entity);HttpResponse response = httpClient.execute(httpPost);String result = EntityUtils.toString(response.getEntity(), "UTF-8");EntityUtils.consume(response.getEntity());return result;
}
文件上传:
public String uploadFile(String url, File file) throws IOException {HttpPost httpPost = new HttpPost(url);// 构建多部分表单MultipartEntityBuilder builder = MultipartEntityBuilder.create();builder.addBinaryBody("file", file, ContentType.APPLICATION_OCTET_STREAM, file.getName());builder.addTextBody("description", "文件描述", ContentType.TEXT_PLAIN);HttpEntity multipart = builder.build();httpPost.setEntity(multipart);HttpResponse response = httpClient.execute(httpPost);String result = EntityUtils.toString(response.getEntity(), "UTF-8");EntityUtils.consume(response.getEntity());return result;
}
5. 使用 CloseableHttpClient(推荐)
public String doGetWithCloseable(String url) {try (CloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {HttpEntity entity = response.getEntity();String result = EntityUtils.toString(entity, "UTF-8");return result;} catch (IOException e) {e.printStackTrace();return null;}
}
6. 工具类封装示例
@Component
public class HttpClientUtil {@Autowiredprivate HttpClient httpClient;public String get(String url) {return get(url, null);}public String get(String url, Map<String, String> headers) {try {HttpGet httpGet = new HttpGet(url);if (headers != null) {for (Map.Entry<String, String> entry : headers.entrySet()) {httpGet.setHeader(entry.getKey(), entry.getValue());}}HttpResponse response = httpClient.execute(httpGet);return EntityUtils.toString(response.getEntity(), "UTF-8");} catch (IOException e) {throw new RuntimeException("HTTP GET 请求失败", e);}}public String postJson(String url, String jsonData) {try {HttpPost httpPost = new HttpPost(url);httpPost.setHeader("Content-Type", "application/json");StringEntity entity = new StringEntity(jsonData, "UTF-8");httpPost.setEntity(entity);HttpResponse response = httpClient.execute(httpPost);return EntityUtils.toString(response.getEntity(), "UTF-8");} catch (IOException e) {throw new RuntimeException("HTTP POST 请求失败", e);}}
}
三、SpringBoot 中的替代方案
除了直接使用 HttpClient,SpringBoot 还提供了其他 HTTP 客户端工具:
1. RestTemplate(Spring 提供)
@Autowired
private RestTemplate restTemplate;String result = restTemplate.getForObject("http://example.com/api", String.class);
2. WebClient(Spring WebFlux,响应式)
@Autowired
private WebClient webClient;String result = webClient.get().uri("http://example.com/api").retrieve().bodyToMono(String.class).block();
3. OpenFeign(声明式客户端,微服务常用)
@FeignClient(name = "user-service", url = "http://localhost:8080")
public interface UserClient {@GetMapping("/users/{id}")User getUser(@PathVariable Long id);
}
四、最佳实践建议
- 使用连接池:避免频繁创建和销毁连接
- 设置超时时间:防止请求长时间挂起
- 异常处理:妥善处理 IOException 等异常
- 资源释放:及时释放 HttpEntity 资源
- 使用工具类:封装常用操作,提高代码复用性
- 选择合适工具:简单场景用 RestTemplate,微服务用 Feign,响应式用 WebClient
五、目前企业中 HTTP 客户端使用情况
1. RestTemplate - 使用最广泛 ⭐⭐⭐⭐⭐
为什么最多?
- Spring 生态内置:无需额外依赖,开箱即用
- 学习成本低:API 简单直观
- 历史悠久:存在大量遗留系统在使用
- 适用场景:传统单体应用、简单微服务
现状:
- 大部分使用 Spring Boot 2.x 的项目都在用
- 虽然 Spring 5.0 后标记为 "维护模式"(不推荐新项目使用)
- 但由于存量项目庞大,仍是使用最多的
// 企业中最常见的用法
@Autowired
private RestTemplate restTemplate;String result = restTemplate.getForObject(url, String.class);
2. OpenFeign - 微服务场景第一选择 ⭐⭐⭐⭐⭐
为什么流行?
- Spring Cloud 标配:微服务架构必备
- 声明式调用:代码简洁优雅
- 功能强大:集成负载均衡、熔断降级、服务发现
适用场景:
- 微服务之间的内部调用
- 需要服务治理的场景
@FeignClient(name = "user-service")
public interface UserClient {@GetMapping("/users/{id}")User getUser(@PathVariable Long id);
}
3. Apache HttpClient - 底层场景 ⭐⭐⭐
使用场景:
- 需要精细控制 HTTP 请求(连接池、超时、重试)
- 第三方 API 对接
- 复杂的 HTTP 场景(文件上传、自定义协议)
现状:
- 大型企业的基础组件层仍在使用
- 通常被封装成工具类供业务使用
- 新项目直接使用的较少
4. WebClient - 新兴力量 ⭐⭐⭐
特点:
- Spring WebFlux 提供的响应式客户端
- 非阻塞、高性能
- Spring 官方推荐的 RestTemplate 替代品
现状:
- 使用率逐年上升
- 响应式编程、高并发场景首选
- 但由于响应式编程学习曲线陡峭,普及率还不如 RestTemplate
企业实际使用排名(2024-2025)
根据实际情况,我估计的使用率排名:
- RestTemplate - 约 40-50%(存量项目多)
- OpenFeign - 约 30-35%(微服务场景)
- Apache HttpClient - 约 15-20%(基础组件)
- WebClient - 约 5-10%(新项目、响应式)
不同场景的选择建议
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 传统单体应用 | RestTemplate | 简单够用 |
| 微服务架构 | OpenFeign | 服务治理完善 |
| 第三方 API 对接 | HttpClient 或 RestTemplate | 灵活可控 |
| 高并发响应式 | WebClient | 非阻塞高性能 |
| 新项目 | WebClient 或 Feign | 官方推荐 |
趋势预测
- RestTemplate:使用率会逐步下降,但短期内仍是主流(存量项目太多)
- OpenFeign:在微服务领域地位稳固
- WebClient:增长最快,未来可能成为主流
- HttpClient:底层场景依然需要,但直接使用会减少
总结
当前企业用得最多的是 RestTemplate,因为它是 Spring 生态的默认选择,学习成本低,存量项目多。
微服务场景下 OpenFeign 是第一选择,已经成为事实标准。
未来趋势是 WebClient,但普及还需要时间。
建议你根据项目实际情况选择:
- 维护老项目:继续用 RestTemplate
- 新建微服务:用 OpenFeign
- 追求性能和新技术:用 WebClient
- 需要底层控制:用 HttpClient
