详细分析HttpClient的基本知识(附Demo实战思路)
目录
- 前言
- 1. Java8 Demo
- 2. Java8 实战
- 3. Java11 Demo
前言
🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF
1. Java8 Demo
下述主体主要针对Java8的版本,后续会有一个特定的Java11版本
推荐使用 Apache HttpClient 4.x,这是在 Java 8 中使用最广泛、最稳定的 HTTP 客户端工具
Apache HttpClient 是 Apache 出品的 HTTP 客户端库,功能强大,适用于:
-
发起 HTTP 请求(GET、POST、PUT、DELETE 等)
-
携带请求头、请求参数
-
设置超时、重定向等策略
-
读取响应状态码、响应体、响应头等
导入相关的依赖包:
<!-- Apache HttpClient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version> <!-- 推荐稳定版本 -->
</dependency>
相关的核心类如下:
类名 | 说明 |
---|---|
CloseableHttpClient | 客户端对象,用于发送请求 |
HttpGet / HttpPost | 表示 HTTP 请求(GET/POST) |
HttpResponse | 响应对象 |
HttpEntity | 请求体或响应体封装 |
EntityUtils | 帮助读取响应体为字符串等形式 |
以下Demo主要用于测试使用,便于理解其用法说明:
Get请求:
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApacheHttpGetDemo {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
CloseableHttpClient client = HttpClients.createDefault();
// 2. 创建 HttpGet 请求对象,并设置 URL
HttpGet get = new HttpGet("https://jsonplaceholder.typicode.com/posts/1");
// 3. 执行请求,获取响应
HttpResponse response = client.execute(get);
// 4. 获取状态码
int statusCode = response.getStatusLine().getStatusCode();
System.out.println("状态码: " + statusCode);
// 5. 获取响应体内容
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println("响应内容: \n" + responseBody);
// 6. 关闭客户端连接
client.close();
}
}
Post请求:
import org.apache.http.HttpResponse;
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;
public class ApacheHttpPostDemo {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
CloseableHttpClient client = HttpClients.createDefault();
// 2. 创建 HttpPost 请求对象
HttpPost post = new HttpPost("https://jsonplaceholder.typicode.com/posts");
// 3. 构造 JSON 请求体(Java 8 用字符串拼接)
String json = "{"
+ "\"title\": \"foo\","
+ "\"body\": \"bar\","
+ "\"userId\": 1"
+ "}";
// 4. 设置请求头和请求体
post.setHeader("Content-Type", "application/json");
post.setEntity(new StringEntity(json, "UTF-8"));
// 5. 发送 POST 请求
HttpResponse response = client.execute(post);
// 6. 读取响应状态码和响应体
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
// 7. 打印结果
System.out.println("状态码: " + statusCode);
System.out.println("响应内容:\n" + responseBody);
// 8. 关闭客户端
client.close();
}
}
上述常用方法总结
✅ 创建客户端:CloseableHttpClient client = HttpClients.createDefault();
✅ GET 请求:HttpGet get = new HttpGet("http://example.com/api");
✅ POST 请求 + JSON
HttpPost post = new HttpPost("http://example.com/api");
post.setHeader("Content-Type", "application/json");
post.setEntity(new StringEntity(jsonData, "UTF-8"));
✅ 发送请求 + 获取响应
HttpResponse response = client.execute(get或post);
int statusCode = response.getStatusLine().getStatusCode();
String body = EntityUtils.toString(response.getEntity(), "UTF-8");
✅ 设置请求头
post.setHeader("Authorization", "Bearer your-token");
post.setHeader("Accept", "application/json");
2. Java8 实战
对接的API接口是一张照片,之后将识别结果返回,比对是否两者一致!
实战中的Demo如下,实战中的Demo主要以思路讲解的方式:
// 某个接口中有所调用API传输文件,得到AI识别结果:
String result = uploadImageAndRecognize(downloadedFile);
// 具体调用的方法参数:
private String uploadImageAndRecognize(File imageFile) throws IOException {
String url = "http://xxxx/recognize";
// 创建HttpClient
CloseableHttpClient httpClient = HttpClients.createDefault();
// 创建 POST 请求
HttpPost uploadFile = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"image",
new FileInputStream(imageFile),
ContentType.APPLICATION_OCTET_STREAM,
imageFile.getName()
);
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
// 执行请求
CloseableHttpResponse response = httpClient.execute(uploadFile);
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String jsonString = EntityUtils.toString(responseEntity);
// 解析 JSON,提取结果
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonString);
JsonNode resultsNode = rootNode.path("results");
if (resultsNode.isArray() && resultsNode.size() > 0) {
return resultsNode.get(0).asText(); // 返回第一个结果
}
}
return null; // 如果解析失败或无结果
}
方法结构核心知识点:
-
CloseableHttpClient httpClient = HttpClients.createDefault();
创建一个 HttpClient 客户端实例
用于执行 HTTP 请求,属于同步阻塞操作 -
HttpPost uploadFile = new HttpPost(url);
创建一个 POST 请求对象,URL 是目标服务端 API 接口 -
MultipartEntityBuilder
用于构建带文件上传的 multipart/form-data 请求体
addBinaryBody() 表示添加文件字段,支持设置内容类型和文件名 -
httpClient.execute(uploadFile)
执行请求,阻塞线程直到响应返回
返回的是 CloseableHttpResponse 对象 -
EntityUtils.toString(responseEntity)
将响应实体转为字符串格式(JSON文本)。 -
ObjectMapper 解析 JSON
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonString);
JsonNode resultsNode = rootNode.path("results");
使用 Jackson 库解析 JSON
path() 用于安全地访问节点,避免 null 指针
- 返回识别结果
if (resultsNode.isArray() && resultsNode.size() > 0) {
return resultsNode.get(0).asText();
}
后续还可进一步优化:
为什么用 CompletableFuture?
异步处理耗时任务(如 HTTP 请求)时,主线程无需等待
非阻塞性能更好,适合高并发场景
支持链式调用、异常处理、并发组合等高级特性
整体改进如下:
✅ 1. 异步化请求(使用 CompletableFuture)
通过异步处理,你可以避免等待 HTTP 请求的过程,减少主线程阻塞,提升性能。使用 CompletableFuture 可以让你并行处理多个请求。
import java.util.concurrent.CompletableFuture;
private CompletableFuture<String> uploadImageAndRecognizeAsync(File imageFile) {
return CompletableFuture.supplyAsync(() -> {
try {
return uploadImageAndRecognize(imageFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
在调用处,可以异步执行,并在适当的时候等待结果
String key = "xxxxx";
Boolean newStatus = redisTemplate.opsForValue().get(key) == null;
if (newStatus) {
File downloadedFile = null;
try {
downloadedFile = downloadFileFromUrl(createReqVO.getImgCntrF());
// 异步调用AI校验接口
CompletableFuture<String> futureResult = uploadImageAndRecognizeAsync(downloadedFile);
// 等待结果并处理
String result = futureResult.get(); // 可以加上超时处理
System.out.println("识别结果: " + result);
// 进一步处理结果...
} catch (Exception e) {
throw new RuntimeException(e);
}
}
✅ 2. 封装 HTTP 请求
为了避免重复代码,你可以把 HTTP 请求的部分封装成一个独立的工具类。这样可以提高代码的可维护性和可重用性。
HttpClientUtils 工具类:
public class HttpClientUtils {
/**
* 发送POST请求上传图片并获取识别结果
* @param url 请求的URL
* @param imageFile 需要上传的图片文件
* @return 识别结果
* @throws IOException
*/
public static String postFile(String url, File imageFile) throws IOException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost uploadFile = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody(
"image",
new FileInputStream(imageFile),
ContentType.APPLICATION_OCTET_STREAM,
imageFile.getName()
);
HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
try (CloseableHttpResponse response = httpClient.execute(uploadFile)) {
HttpEntity responseEntity = response.getEntity();
if (responseEntity != null) {
String jsonString = EntityUtils.toString(responseEntity);
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonString);
JsonNode resultsNode = rootNode.path("results");
if (resultsNode.isArray() && resultsNode.size() > 0) {
return resultsNode.get(0).asText(); // 返回第一个识别结果
}
}
}
}
return null; // 如果没有获取到识别结果
}
}
然后,调用时直接使用工具类:
String key = "xxxx";
Boolean newStatus = redisTemplate.opsForValue().get(key) == null;
if (newStatus) {
File downloadedFile = null;
try {
downloadedFile = downloadFileFromUrl(createReqVO.getImgCntrF());
// 调用工具类进行图片上传与识别
String result = HttpClientUtils.postFile("http://10.197.2.16:5000/api/recognize", downloadedFile);
System.out.println("识别结果: " + result);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
✅ 3. 异常处理与重试机制
考虑到网络请求的可能失败,可以加入重试机制。比如在请求失败时可以重试几次,使用 RetryTemplate 或 Spring Retry 可以实现。
下面是一个简单的重试实现:
import org.springframework.retry.support.RetryTemplate;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
public class RetryHttpClientUtils {
private static RetryTemplate createRetryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
// 设置重试策略:最多重试3次
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(3);
retryTemplate.setRetryPolicy(retryPolicy);
// 设置重试的退避策略:指数退避
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(1000); // 初始间隔时间:1秒
backOffPolicy.setMultiplier(2); // 每次间隔时间倍增
retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
public static String postFileWithRetry(String url, File imageFile) throws IOException {
RetryTemplate retryTemplate = createRetryTemplate();
return retryTemplate.execute(context -> HttpClientUtils.postFile(url, imageFile));
}
}
3. Java11 Demo
后续发现一个野生的Java11版本
Java 11 之后,HttpClient 成为了标准库的一部分(位于 java.net.http 包中)
核心类:
类名 | 说明 |
---|---|
HttpClient | HTTP 客户端,用于发送请求、接收响应 |
HttpRequest | 表示一个 HTTP 请求(如 GET/POST) |
HttpResponse | 表示响应结果,包括状态码、响应体等 |
HttpRequest.BodyPublishers | 用于构造请求体 |
HttpResponse.BodyHandlers | 用于处理响应体 |
基本的逻辑步骤如下:
-
创建 HttpClient 客户端对象
-
构造 HttpRequest 请求对象
-
发送请求并获取 HttpResponse 响应对象
Get请求:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class HttpClientGetDemo {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
HttpClient client = HttpClient.newHttpClient();
// 2. 构造 GET 请求(指定 URI)
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://jsonplaceholder.typicode.com/posts/1"))
.GET() // 默认就是 GET
.build();
// 3. 发送请求并获取响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 4. 打印状态码和响应体
System.out.println("状态码: " + response.statusCode());
System.out.println("响应内容: \n" + response.body());
}
}
Post请求:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
public class HttpClientPostDemo {
public static void main(String[] args) throws Exception {
// 1. 创建 HttpClient 实例
HttpClient client = HttpClient.newHttpClient();
// 2. 构造 POST 请求,发送 JSON 数据
String json = """
{
"title": "foo",
"body": "bar",
"userId": 1
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://jsonplaceholder.typicode.com/posts"))
.header("Content-Type", "application/json") // 设置请求头
.POST(BodyPublishers.ofString(json)) // 设置请求体
.build();
// 3. 发送请求并接收响应
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// 4. 打印状态码和响应内容
System.out.println("状态码: " + response.statusCode());
System.out.println("响应内容: \n" + response.body());
}
}
常用方法分析
HttpClient 创建
HttpClient client = HttpClient.newHttpClient(); // 默认配置
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
HttpRequest 构建方法
// GET 请求
HttpRequest.newBuilder().uri(new URI("...")).GET().build();
// POST 请求
HttpRequest.newBuilder().uri(new URI("..."))
.POST(BodyPublishers.ofString("请求体"))
.build();
// 设置请求头
.header("Content-Type", "application/json")
HttpResponse 处理方式
HttpResponse.BodyHandlers.ofString(); // 将响应体转为字符串
HttpResponse.BodyHandlers.ofByteArray(); // 转为字节数组
HttpResponse.BodyHandlers.ofFile(Path.of("output.txt")); // 写入文件