Apache HttpClient 是 Java 領域最成熟的 HTTP 客戶端庫,支援 HTTP/1.1、連接池、認證、攔截器等企業級特性。本文基於 HttpClient 4.5+,提供可直接複製運行的 GET/POST 完整示例,涵蓋 Header 設置、表單參數、JSON 參數、超時配置、響應解析等高頻場景。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<!-- JSON 處理可選 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency>
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HttpClientUtil {
private static final CloseableHttpClient HTTP_CLIENT = HttpClients.custom()
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000) // 連接超時 5s
.setSocketTimeout(10000) // 讀取超時 10s
.setConnectionRequestTimeout(1000)
.build())
.build();
/** 關閉客戶端(應用關閉時調用) */
public static void close() throws IOException {
HTTP_CLIENT.close();
}
/**
* GET 請求
* @param url 請求地址
* @param headers 請求頭 Map
* @param params URL 參數 Map(自動拼接到 URL)
* @return 響應字符串
*/
public static String doGet(String url, Map headers, Map params) throws IOException {
// 1. 拼接參數
if (params != null && !params.isEmpty()) {
StringBuilder sb = new StringBuilder(url.contains("?") ? "&" : "?");
params.forEach((k, v) -> sb.append(k).append('=').append(v).append('&'));
sb.deleteCharAt(sb.length() - 1);
url += sb;
}
// 2. 創建請求
HttpGet httpGet = new HttpGet(url);
if (headers != null) {
headers.forEach(httpGet::setHeader);
}
// 3. 執行並解析響應
return execute(httpGet);
}
/**
* POST 表單請求 (application/x-www-form-urlencoded)
*/
public static String doPostForm(String url, Map headers, Map formParams) throws IOException {
HttpPost httpPost = new HttpPost(url);
if (headers != null) {
headers.forEach(httpPost::setHeader);
}
if (formParams != null && !formParams.isEmpty()) {
List pairs = new ArrayList<>();
formParams.forEach((k, v) -> pairs.add(new BasicNameValuePair(k, v)));
httpPost.setEntity(new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8));
}
return execute(httpPost);
}
/**
* POST JSON 請求 (application/json)
*/
public static String doPostJson(String url, Map headers, String jsonBody) throws IOException {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
if (headers != null) {
headers.forEach(httpPost::setHeader);
}
if (jsonBody != null) {
httpPost.setEntity(new org.apache.http.entity.StringEntity(jsonBody, StandardCharsets.UTF_8));
}
return execute(httpPost);
}
/** 統一執行與響應處理 */
private static String execute(org.apache.http.client.methods.HttpUriRequest request) throws IOException {
try (CloseableHttpResponse response = HTTP_CLIENT.execute(request)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
return EntityUtils.toString(entity, StandardCharsets.UTF_8);
}
return "";
}
}
}
public String getDailySummary(String accessToken) throws IOException {
Map headers = Map.of("Authorization", "Bearer " + accessToken);
return HttpClientUtil.doGet("https://api.microsofthealth.net/v1/me/Summaries/Daily", headers, null);
}
public String getOAuthToken(String clientId, String redirectUri, String clientSecret, String code) throws IOException {
Map form = Map.of(
"client_id", clientId,
"redirect_uri", redirectUri,
"client_secret", clientSecret,
"code", code,
"grant_type", "authorization_code"
);
Map headers = Map.of("Content-Type", "application/x-www-form-urlencoded");
return HttpClientUtil.doPostForm("https://login.live.com/oauth20_token.srf", headers, form);
}
// 需 Jackson 依賴
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(Map.of("userId", 123, "action", "login"));
Map headers = Map.of("Authorization", "Bearer token_xxx");
String resp = HttpClientUtil.doPostJson("https://api.example.com/action", headers, json);
| 需求 | 配置方式 |
|---|---|
| 連接池複用 | HttpClients.custom().setMaxConnTotal(200).setMaxConnPerRoute(50) |
| HTTPS 忽略證書驗證(測試環境) | 實現 TrustStrategy 返回 true,構建 SSLContext 並 .setSSLContext() |
| 自動重試 | .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) |
| 攔截器(日誌/簽名) | .addInterceptorLast(new HttpRequestInterceptor() {...}) |
| 多部分/文件上傳 | 使用 MultipartEntityBuilder 構建 HttpEntity |
UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8)、EntityUtils.toString(entity, StandardCharsets.UTF_8)。CloseableHttpClient 線程安全,全局僅需一個實例,應用關閉時統一 close()。org.apache.httpcomponents.client5:httpclient5),API 更現代、支援 HTTP/2、異步非阻塞。HttpClient 4.x 雖屬經典版本,但在大量存量項目中仍廣泛使用。掌握 工具類封裝、Header/參數/Body 多樣化構建、統一異常與資源處理,即可應對 90% 以上的 HTTP 交互場景。新項目優先考慮 HttpClient 5.x 或 WebClient (Spring WebFlux) 獲得更現代的體驗。