HttpUtils
工具类
提供基于 Java 11+ java.net.http.HttpClient
的通用 HTTP 请求工具方法,支持 GET、POST、PUT、DELETE 等操作,并可自动解析 JSON 响应为 Java 对象。
一、概述
HttpUtils
是一个轻量级、线程安全的 HTTP 客户端工具类,封装了以下能力:
- 使用 Java 11+ 内置的
HttpClient
(非 Apache HttpClient 或 OkHttp) - 支持 GET / POST / PUT / DELETE 请求
- 自动拼接 URL 查询参数(
Map<String, String>
) - 自动设置通用请求头(如
User-Agent
,Accept
) - 支持自定义请求头
- 请求体自动序列化为 JSON(使用
JsonUtils
) - 响应体自动反序列化为指定 Java 类型(对象或集合)
- 内置日志记录(请求 URL、Header、Body、响应状态码等)
- 统一异常处理(抛出
ServiceException
)
注意:该工具类 禁止设置受限 HTTP 头(如
Connection
,Host
,Content-Length
等),否则会抛出IllegalArgumentException
。
二、配置项
配置项 | 默认值 | 说明 |
---|---|---|
CONNECT_TIMEOUT | 30 秒 | HTTP 连接超时时间 |
HttpClient | followRedirects(HttpClient.Redirect.NORMAL) | 自动跟随 3xx 重定向 |
三、核心方法
1. GET 请求(推荐)
方法签名
public static <T> T get(String url, Class<T> clazz)
public static <T> T get(String url, Map<String, String> params, Class<T> clazz)
public static <T> T get(String url, Map<String, String> headers, Map<String, String> params, Class<T> clazz)
参数说明
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
url | String | 是 | 请求地址(如 https://api.example.com/users ) |
params | Map<String, String> | 否 | 查询参数,自动拼接到 URL 后(如 ?page=1&size=10 ) |
headers | Map<String, String> | 否 | 自定义请求头(会与通用头合并) |
clazz | Class<T> | 是 | 期望的响应类型(如 User.class , Map.class ) |
使用示例
// 1. 获取单个对象
User user = HttpUtils.get("https://api.example.com/user/1", User.class);
// 2. 带查询参数
Map<String, String> params = Map.of("status", "active");
List<User> users = HttpUtils.get("https://api.example.com/users", params, new TypeReference<List<User>>(){}.getType());
// ⚠️ 注意:当前仅支持 Class<T>,不支持 TypeReference(见【限制】)
// 3. 自定义 Header
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer xxx");
String result = HttpUtils.get("https://api.example.com/data", headers, null, String.class);
2. POST 请求
方法签名
public static <T> T post(String url, Object body, Class<T> clazz)
public static <T> T post(String url, Map<String, String> headers, Object body, Class<T> clazz)
public static <T> T post(String url, Map<String, String> headers, Map<String, String> params, Object body, Class<T> clazz)
参数说明
参数 | 说明 |
---|---|
body | 请求体对象,会自动通过 JsonUtils.toJsonString() 转为 JSON 字符串 |
其他参数 | 同 GET 方法 |
使用示例
User newUser = new User("Alice", "alice@example.com");
User created = HttpUtils.post("https://api.example.com/users", newUser, User.class);
3. PUT / DELETE 请求(底层方法)
目前未提供泛型解析的便捷方法,需使用底层
sendPut
/sendDelete
+ 手动解析。
String response = HttpUtils.sendDelete(
"https://api.example.com/users/1",
null, // headers
null, // params
HttpResponse.BodyHandlers.ofString()
);
User user = JsonUtils.parseObject(response, User.class);
四、源代码:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpHeaders;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.utils.StringUtils;
/**
* 通用http发送方法
*
*
*/
public class HttpUtils {
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
// 连接超时时间,单位秒
private static final Integer CONNECT_TIMEOUT = 30;
/**
* HTTP客户端实例
*/
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(CONNECT_TIMEOUT))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
/**
* 发送 GET 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T get(String url,
Map<String, String> headers,
Map<String, String> params,
Class<T> clazz) {
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendGet(url, headers, params, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 发送 GET 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param params 请求参数
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T get(String url,
Map<String, String> params,
Class<T> clazz) {
HashMap<String, String> headers = new HashMap<>();
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendGet(url, headers, params, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 发送 GET 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T get(String url,
Class<T> clazz) {
HashMap<String, String> headers = new HashMap<>();
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendGet(url, headers, null, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 发送 POST 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param body 请求体
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T post(String url,
Map<String, String> headers,
Map<String, String> params,
Object body,
Class<T> clazz) {
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendPost(url, headers, params, body, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 发送 POST 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param headers 请求头
* @param body 请求体
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T post(String url,
Map<String, String> headers,
Object body,
Class<T> clazz) {
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendPost(url, headers, null, body, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 发送 POST 请求并将响应解析为指定类型的对象
*
* @param url 请求地址
* @param body 请求体
* @param clazz 响应对象类型
* @return 响应对象
*/
public static <T> T post(String url,
Object body,
Class<T> clazz) {
HashMap<String, String> headers = new HashMap<>();
setCommonHeader(headers);
HttpResponse.BodyHandler<String> stringHandler = HttpResponse.BodyHandlers.ofString();
String json = sendPost(url, headers, null, body, stringHandler);
return JsonUtils.parseObject(json, clazz);
}
/**
* 设置通用请求头
*
* @param headers 请求头
*/
public static void setCommonHeader(Map<String, String> headers) {
if (headers != null) {
headers.putIfAbsent("Accept", "*/*");
String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36";
headers.putIfAbsent("User-Agent", userAgent);
}
}
/**
* 发送 GET 请求
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param responseBodyHandler 响应体处理器 通过 HttpResponse.BodyHandler 创建
* @return 响应体
*/
public static <T> T sendGet(String url,
Map<String, String> headers,
Map<String, String> params,
HttpResponse.BodyHandler<T> responseBodyHandler) {
// 构建请求
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
setRequestHeader(requestBuilder, headers);
String fullUrl = setRequestParams(url, params);
requestBuilder.uri(URI.create(fullUrl));
requestBuilder.GET();
HttpRequest request = requestBuilder.build();
// 发送请求
return send(request, responseBodyHandler, null);
}
/**
* 发送 GET 请求
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param responseBodyHandler 响应体处理器 响应体处理器 通过 HttpResponse.BodyHandler 创建
* @return 响应体
*/
public static <T> T sendDelete(String url,
Map<String, String> headers,
Map<String, String> params,
HttpResponse.BodyHandler<T> responseBodyHandler) {
// 构建请求
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
setRequestHeader(requestBuilder, headers);
String fullUrl = setRequestParams(url, params);
requestBuilder.uri(URI.create(fullUrl));
requestBuilder.DELETE();
HttpRequest request = requestBuilder.build();
// 发送请求
return send(request, responseBodyHandler, null);
}
/**
* 发送 POST 请求
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param body 请求体
* @param responseBodyHandler 响应体处理器 响应体处理器 通过 HttpResponse.BodyHandler 创建
* @return 响应体
*/
public static <T> T sendPost(String url,
Map<String, String> headers,
Map<String, String> params,
Object body,
HttpResponse.BodyHandler<T> responseBodyHandler) {
// 构建请求
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
setRequestHeader(requestBuilder, headers);
String fullUrl = setRequestParams(url, params);
requestBuilder.uri(URI.create(fullUrl));
if (body != null) {
requestBuilder.POST(
HttpRequest.BodyPublishers.ofString(
Objects.requireNonNull(JsonUtils.toJsonString(body))));
} else {
requestBuilder.POST(HttpRequest.BodyPublishers.noBody());
}
HttpRequest request = requestBuilder.build();
// 发送请求
return send(request, responseBodyHandler, body != null ? JsonUtils.toJsonString(body) : null);
}
/**
* 发送 POST 请求
*
* @param url 请求地址
* @param headers 请求头
* @param params 请求参数
* @param body 请求体
* @param responseBodyHandler 响应体处理器 响应体处理器 通过 HttpResponse.BodyHandler 创建
* @param <T>
* @return 响应体
*/
public static <T> T sendPut(String url,
Map<String, String> headers,
Map<String, String> params,
Object body,
HttpResponse.BodyHandler<T> responseBodyHandler) {
// 构建请求
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder();
setRequestHeader(requestBuilder, headers);
String fullUrl = setRequestParams(url, params);
requestBuilder.uri(URI.create(fullUrl));
if (body != null) {
requestBuilder.PUT(
HttpRequest.BodyPublishers.ofString(
Objects.requireNonNull(JsonUtils.toJsonString(body))));
} else {
requestBuilder.PUT(HttpRequest.BodyPublishers.noBody());
}
HttpRequest request = requestBuilder.build();
// 发送请求
return send(request, responseBodyHandler, body != null ? JsonUtils.toJsonString(body) : null);
}
/**
* 发送请求
*
* @param request 请求对象
* @param responseBodyHandler 响应体处理器 通过 HttpResponse.BodyHandler 创建
* @return 响应体
*/
private static <T> T send(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler, String body) {
// 打印请求信息
String method = request.method();
URI uri = request.uri();
HttpHeaders headers = request.headers();
if (body != null && !body.isEmpty()) {
log.info("HTTP工具 send{} - url={},\n header={},\n \n body={} ",
method,
uri,
headers.map(),
body);
} else {
log.info("HTTP工具 send{} - url={},\n header={}",
method,
uri,
headers.map());
}
//发送请求
try {
HttpResponse<T> response = HTTP_CLIENT.send(request, responseBodyHandler);
log.info("HTTP工具 请求返回 - {}", response);
T resBody = response.body();
if (resBody instanceof String) {
log.info("HTTP工具 响应 - status={}, body={}", response.statusCode(), resBody);
} else {
// 非字符串类型只打印类型和状态码
log.info("HTTP工具 响应 - status={}, bodyType={}",
response.statusCode(),
body == null ? "null" : body.getClass().getSimpleName());
}
return resBody;
} catch (Exception e) {
log.error("HTTP工具 send{} 请求异常:\n url={}", method, uri, e);
throw new ServiceException("HTTP POST failed" + e.getMessage());
}
}
/**
* 设置请求头
*
* @param requestBuilder 请求构建器
* @param header 请求头
*/
private static void setRequestHeader(HttpRequest.Builder requestBuilder, Map<String, String> header) {
if (header != null && !header.isEmpty()) {
for (Map.Entry<String, String> entry : header.entrySet()) {
requestBuilder.header(entry.getKey(), entry.getValue());
}
}
}
/**
* 设置请求参数
*
* @param url 请求地址
* @param params 请求参数
* @return 完整请求地址
*/
private static String setRequestParams(String url, Map<String, String> params) {
if (params == null || params.isEmpty()) {
return url;
}
String queryString = params.entrySet().stream()
.map(e -> URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8) + "=" +
URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
return url + "?" + queryString;
}
}