hutool工具的HttpUtil和HttpRequest

58 阅读4分钟

cn.hutool.http.HttpUtilcn.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());
    });

三、核心区别对比

特性HttpUtilHttpRequest
类型静态工具类链式请求构建器
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 对象。

为什么这样设计?(设计优势)

  1. 链式调用(Fluent API) :代码可读性极高,像写句子一样构建请求。
  2. 灵活性:可以自由组合各种配置,易于扩展。
  3. 面向对象:每个请求是一个独立的对象,可以复用、修改。
  4. 延迟执行:直到调用 .execute() 才真正发起请求,便于构建复杂逻辑。