引言
在现代应用程序开发中,网络请求是必不可少的功能之一。无论是访问第三方API、微服务之间的通信,还是请求远程数据,都需要通过HTTP协议实现。
在Java中,java.net.HttpURLConnection、Apache的HttpClient库以及OkHttp等库提供了丰富的HTTP请求功能,但这些API有时需要较多的样板代码,因此封装一个通用的网络请求工具类(如HttpUtils或HttpClientUtils)可以简化开发流程,提高效率。
HttpUtils 工具类设计
HttpUtils 是一个封装了常用HTTP请求操作的工具类,基于 Apache HttpClient 实现。这个工具类支持 GET、POST、PUT、DELETE 等常见请求方法,并提供了请求头设置、参数传递、响应处理、超时设置等功能。
以下是 HttpUtils 工具类的主要功能:
- 发送 GET 请求:用于从服务器获取资源。
- 发送 POST 请求:用于向服务器提交数据。
- 发送 PUT 请求:用于更新服务器上的资源。
- 发送 DELETE 请求:用于删除服务器上的资源。
- 发送 PATCH 请求:对资源进行部分更新。它的主要特点是只更新资源的部分属性,而不是像PUT那样替换整个资源
- 设置请求头:支持自定义请求头,如Content-Type、Authorization等。
- 设置cookies
- 超时设置:支持连接超时和读取超时的设置。
HttpUtils 工具类的实现
import com.alibaba.fastjson2.JSONObject;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
public class HttpUtils {
private static final RestTemplate REST_TEMPLATE;
static {
HttpComponentsClientHttpRequestFactory factory =
new HttpComponentsClientHttpRequestFactory(
HttpClients.custom()
.setMaxConnTotal(512) // 设置整个连接池的最大连接数为 512
.setMaxConnPerRoute(32) // 设置每个路由(如相同域名)的最大连接数为 32
.build()
);
// 表示建立TCP连接的超时时间为5000毫秒(5秒)。
// 若超过此时限仍未完成连接建立,将抛出ConnectTimeoutException。该设置适用于网络延迟较高或目标服务不可达的场景
factory.setConnectTimeout(5000);
// 定义从服务器读取数据的超时时间为10000毫秒(10秒)。
// 若服务器在此时限内未返回完整响应数据,将触发SocketTimeoutException。适用于处理响应较慢的API接口
factory.setReadTimeout(10000);
REST_TEMPLATE = new RestTemplate(factory);
}
// GET请求方法
public static String executeGet(String url, JSONObject params,String contentType,Map<String, String> cookies) {
return executeRequest(url, params, HttpMethod.GET.name(), contentType,cookies);
}
// POST请求方法
public static String executePost(String url, JSONObject params,String contentType,Map<String, String> cookies) {
return executeRequest(url, params, HttpMethod.POST.name(), contentType,cookies);
}
// PUT请求方法
public static String executePut(String url, JSONObject params, String contentType,Map<String, String> cookies) {
return executeRequest(url, params, HttpMethod.PUT.name(), contentType,cookies);
}
// DELETE请求方法
public static String executeDelete(String url, JSONObject params, String contentType,Map<String, String> cookies) {
return executeRequest(url, params, HttpMethod.DELETE.name(), contentType,cookies);
}
// PATCH请求方法
public static String executePatch(String url, JSONObject params, String contentType,Map<String, String> cookies) {
return executeRequest(url, params, HttpMethod.PATCH.name(), contentType,cookies);
}
// 原始完整参数方法保留
private static String executeRequest(String url, JSONObject params,
String method, String contentType,Map<String, String> cookies) {
try {
// 创建URL构建器
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(url);
// 处理GET请求的参数
if (HttpMethod.GET.name().equalsIgnoreCase(method)) {
// 将每个参数添加到URL查询字符串
for (Map.Entry<String, Object> param : params.entrySet()) {
urlBuilder.queryParam(param.getKey(), param.getValue());
}
// 构建最终URL并编码特殊字符
url = urlBuilder.build()
.encode(StandardCharsets.UTF_8)
.toUriString();
}
HttpHeaders headers = new HttpHeaders();
//设置cookies
if (cookies != null) {
addCookies(headers, cookies);
}
//设置请求体
Object requestBody = prepareRequestBody(params, method, contentType, headers);
//开始调用
ResponseEntity<String> response = REST_TEMPLATE.exchange(
url,
Objects.requireNonNull(HttpMethod.resolve(method.toUpperCase())),
new HttpEntity<>(requestBody, headers),
String.class
);
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("HTTP请求失败: " + response.getStatusCode());
}
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("HTTP请求异常", e);
}
}
private static Object prepareRequestBody(JSONObject params, String method,
String contentType, HttpHeaders headers) {
if (HttpMethod.GET.name().equalsIgnoreCase(method)) return null;
switch(contentType.toLowerCase()) {
case "application/json":
headers.setContentType(MediaType.APPLICATION_JSON);
return params;
case "application/x-www-form-urlencoded":
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return buildFormData(params);
default:
throw new IllegalArgumentException("不支持的Content-Type: " + contentType);
}
}
private static MultiValueMap<String, String> buildFormData(JSONObject params) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
params.forEach((k, v) -> formData.add(k, v.toString()));
return formData;
}
public static void addCookies(HttpHeaders headers, Map<String, String> cookies) {
if (cookies != null && !cookies.isEmpty()) {
List<String> cookieList = new ArrayList<>();
cookies.forEach((k, v) -> cookieList.add(k + "=" + v));
headers.put(HttpHeaders.COOKIE, cookieList);
}
}
}
这是一个基于Spring框架的HTTP请求工具类,主要使用RestTemplate
和Apache HttpClient实现HTTP通信功能。以下是对该工具类的详细解析:
1、RestTemplate
初始化
通过HttpComponentsClientHttpRequestFactory
配置底层HTTP客户端,关键参数包括:
setMaxConnTotal(512)
:全局最大连接数限制setMaxConnPerRoute(32)
:单域名最大连接数限制setConnectTimeout(5000)
:TCP连接超时时间(5秒)setReadTimeout(10000)
:数据读取超时时间(10秒)
2、HTTP方法封装
- 支持
GET/POST/PUT/DELETE/PATCH
方法,统一调用executeRequest
处理 - 通过
HttpMethod.resolve()
动态解析请求类型,避免硬编码
3、参数处理
- GET请求:参数拼接至URL,自动进行UTF-8编码
- POST/PUT等请求:根据
contentType
处理请求体:x-www-form-urlencoded
:转换为MultiValueMap
表单数据。application/json
:直接传递JSON对象
4、Cookie管理
addCookies()
方法将Map格式的Cookie转换为HTTP头格式(key=value)
5、异常处理
- 统一捕获异常并包装为
RuntimeException
- 检查响应状态码,非2xx响应抛出明确异常
测试用例参考
我们启动本地xxl-job,然后访问用户列表查询页面
相关请求参数如下
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.utils.HttpUtils;
import lombok.Data;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Http远程调用测试
*/
public class TestHttp {
// 新增嵌套实体类
@Data
private static class UserDetail {
private Integer id;
private String username;
private String password;
}
@Test
public void testHttp() {
try {
//模拟请求参数
JSONObject params = new JSONObject();
params.put("role", -1);
params.put("start",0);
params.put("length",10);
//模拟请求cookies
Map<String, String> cookies = new HashMap<>();
cookies.put("XXL_JOB_LOGIN_IDENTITY", "7b226964223a312c22757365726e616d65223a2261646d696e222c2270617373776f7264223a226531306164633339343962613539616262653536653035376632306638383365222c22726f6c65223a312c227065726d697373696f6e223a6e756c6c7d");
//开始远程调用
String str = HttpUtils.executePost("http://localhost:9000/xxl-job-admin/user/pageList",
params,
MediaType.APPLICATION_FORM_URLENCODED_VALUE,
cookies
);
//解析反参
System.out.println(str);
JSONObject jsonObject = JSONObject.parseObject(str);
JSONArray dataArray = jsonObject.getJSONArray("data");
List<UserDetail> list = dataArray.toList(UserDetail.class);
System.out.println(list);
}catch (Exception e){
e.printStackTrace();
}
}
}
最后成功返回数据