cn.hutool.http.HttpUtil 和 cn.hutool.http.HttpRequest 是 Hutool 这个 Java 工具库中提供的两个用于发起 HTTP 请求的工具,它们定位不同,一个偏向简单快捷,另一个偏向灵活控制。
简单来说:
HttpUtil:是一个静态工具类,提供一系列static方法,适合快速、简单的 HTTP 调用。HttpRequest:是一个链式构建的请求对象,提供 fluent API,适合需要精细控制请求细节的场景。
一、HttpUtil:静态工具,简单粗暴
特点
- 使用方式:直接调用静态方法。
- 优点:代码极其简洁,一行搞定,适合快速开发、脚本化任务。
- 缺点:灵活性差,难以控制复杂的请求头、请求体、超时等。
常用方法示例
import cn.hutool.http.HttpUtil;
// GET 请求,获取字符串
String result = HttpUtil.get("https://httpbin.org/get");
// POST 提交表单
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("name", "John");
paramMap.put("age", 30);
String result = HttpUtil.post("https://httpbin.org/post", paramMap);
// 下载文件
HttpUtil.downloadFile("https://example.com/file.pdf", FileUtil.file("d:/file.pdf"));
// 上传文件
HashMap<String, Object> form = new HashMap<>();
form.put("file", FileUtil.file("d:/test.jpg"));
HttpUtil.post("https://httpbin.org/post", form);
适用场景
- 简单的 REST API 调用。
- 获取网页内容。
- 快速测试接口。
- 对请求控制要求不高的场景。
二、HttpRequest:链式构建,灵活强大
特点
-
使用方式:通过
HttpRequest.url().method().header().body().execute()这样的链式调用构建请求。 -
优点:
- 高度灵活:可以精细控制每一个请求细节。
- 链式 API:代码可读性好,易于构建复杂请求。
- 支持更多特性:如 Cookie 管理、连接池、异步请求、文件上传下载等。
-
缺点:代码相对
HttpUtil稍长。
常用用法示例
java
编辑
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.Method;
// GET 请求
String result = HttpRequest.get("https://httpbin.org/get")
.header("User-Agent", "Hutool") // 添加请求头
.timeout(5000) // 设置超时
.execute()
.body();
// POST JSON
String json = "{"name": "John", "age": 30}";
String result = HttpRequest.post("https://httpbin.org/post")
.header("Content-Type", "application/json")
.body(json)
.execute()
.body();
// 带 Cookie 的请求
HttpResponse response = HttpRequest.get("https://httpbin.org/cookies")
.cookie("token=abc123; userId=1001")
.execute();
List<Cookie> cookies = response.getCookies(); // 获取响应中的 Cookie
// 异步请求
HttpRequest.get("https://httpbin.org/get")
.async()
.execute()
.thenAccept(resp -> {
System.out.println(resp.body());
});
三、核心区别对比
| 特性 | HttpUtil | HttpRequest |
|---|---|---|
| 类型 | 静态工具类 | 链式请求构建器 |
| API 风格 | 函数式调用 HttpUtil.get(url) | 链式调用 HttpRequest.get(url).header().execute() |
| 灵活性 | ⭐⭐ 低 | ⭐⭐⭐⭐⭐ 高 |
| 代码简洁性 | ⭐⭐⭐⭐⭐ 极简 | ⭐⭐⭐ 适中 |
| 请求头控制 | 有限(部分方法支持) | ✅ 完全支持 .header() |
| 请求体控制 | 有限 | ✅ 完全支持 .body() |
| 超时设置 | 全局或简单参数 | ✅ 每个请求独立设置 .timeout() |
| Cookie 管理 | 弱 | ✅ 支持 .cookie() 和 response.getCookies() |
| 异步支持 | ❌ 不支持 | ✅ 支持 .async() |
| 连接池 | ❌ 不支持 | ✅ 支持配置 |
| 适用场景 | 简单、快速调用 | 复杂、需要控制的请求 |
四、底层关系
HttpUtil的底层实际上就是封装了HttpRequest。- 当你调用
HttpUtil.get(url)时,它内部会创建一个HttpRequest对象,设置 GET 方法,然后执行。 - 所以
HttpRequest是更底层、更核心的组件。
五、如何选择?
| 你的需求 | 推荐工具 |
|---|---|
| 只是想快速获取一个 URL 的内容 | ✅ HttpUtil.get(url) |
| 提交一个简单的表单数据 | ✅ HttpUtil.post(url, paramMap) |
| 需要设置自定义请求头、超时、Content-Type | ✅ HttpRequest |
| 需要发送 JSON、XML 等原始数据 | ✅ HttpRequest |
| 需要处理 Cookie | ✅ HttpRequest |
| 需要异步非阻塞调用 | ✅ HttpRequest.async() |
| 高并发场景,需要连接池 | ✅ HttpRequest(可配置) |
六、总结
在实际开发中,可以结合使用:
- 用
HttpUtil处理简单的、常规的 HTTP 调用。 - 用
HttpRequest处理复杂的、需要定制的 HTTP 请求。
七、为什么HttpRequest提供的也是静态方法,但不是静态工具类
HttpRequest 不是静态工具类,它不提供静态方法来执行请求,而是一个通过静态工厂方法创建实例的请求构建器(Builder) 。
核心区别:静态方法调用 vs. 实例方法链式调用
1. HttpUtil:真正的静态工具类
// ✅ 调用的是 static 静态方法
String result = HttpUtil.get("https://httpbin.org/get");
String result2 = HttpUtil.post("https://httpbin.org/post", paramMap);
get和post是HttpUtil类的static方法。- 你不需要创建
HttpUtil的实例。 - 这是典型的工具类用法。
2. HttpRequest:不是静态工具类
// ❌ 错误理解:以为 .get() 是静态方法
// String result = HttpRequest.get("...").header().execute().body();
// ✅ 正确理解:
HttpRequest request = HttpRequest.get("https://httpbin.org/get");
// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
// 这是一个【静态工厂方法】,返回一个 HttpRequest 实例
// 然后在【实例】上进行链式调用
String result = request
.header("User-Agent", "Hutool")
.timeout(5000)
.execute() // 这也是一个实例方法
.body(); // 这也是一个实例方法
或者更常见的写法(链式一行):
String result = HttpRequest.get("https://httpbin.org/get")
.header("User-Agent", "Hutool")
.timeout(5000)
.execute()
.body();
关键概念解析
| 概念 | 说明 |
|---|---|
HttpRequest.get(String url) | 这是一个 static 静态工厂方法。它的作用是创建并返回一个 HttpRequest 实例,并设置 URL 和 GET 方法。它本身不执行请求。 |
.header(), .timeout(), .execute() | 这些都是 实例方法。它们在 HttpRequest 对象实例上调用,并且通常返回 this(自身),从而实现链式调用(Fluent API) 。 |
execute() | 这是最关键的实例方法,它真正发起 HTTP 请求,并返回一个 HttpResponse 对象。 |
为什么这样设计?(设计优势)
- 链式调用(Fluent API) :代码可读性极高,像写句子一样构建请求。
- 灵活性:可以自由组合各种配置,易于扩展。
- 面向对象:每个请求是一个独立的对象,可以复用、修改。
- 延迟执行:直到调用
.execute()才真正发起请求,便于构建复杂逻辑。