Skip to content

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_TIMEOUT30HTTP 连接超时时间
HttpClientfollowRedirects(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)

参数说明

参数类型必填说明
urlString请求地址(如 https://api.example.com/users
paramsMap<String, String>查询参数,自动拼接到 URL 后(如 ?page=1&size=10
headersMap<String, String>自定义请求头(会与通用头合并)
clazzClass<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;
    }
}
最近更新