引言
在現代應用程序開發中,網絡請求是必不可少的功能之一。無論是訪問第三方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();//設置cookiesif (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 {// 新增嵌套實體類@Dataprivate static class UserDetail {private Integer id;private String username;private String password;}@Testpublic void testHttp() {try {//模擬請求參數JSONObject params = new JSONObject();params.put("role", -1);params.put("start",0);params.put("length",10);//模擬請求cookiesMap<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();}}
}
最后成功返回數據