Apache HttpClient 是 Java 生態系中最廣泛使用的 HTTP 客端端庫,相較於 JDK 內建的 HttpURLConnection,它提供了更豐富的 API、連線池管理、自動重試、Cookie 管理、攔截器機制等企業級功能。本文基於 HttpClient 4.3+ 版本,系統性介紹核心用法與實戰場景。
| 組件 | 職責 |
|---|---|
CloseableHttpClient | HTTP 客戶端主介面,執行請求、管理連線池 |
HttpGet/HttpPost/HttpPut... | HTTP 方法請求物件 |
HttpEntity | 請求/回應內容實體(表單、JSON、檔案、字串) |
CloseableHttpResponse | 回應物件,包含狀態碼、Header、Entity |
RequestConfig | 請求層級配置(超時、重導向、Cookie 政策) |
HttpClientBuilder | 建構器模式建立客戶端實例 |
// 1. 建立客戶端(建議單例或連線池複用)
CloseableHttpClient client = HttpClients.createDefault();
try {
// 2. 建立請求物件
HttpGet request = new HttpGet("https://api.example.com/users/123");
// 3. 設定 Header
request.setHeader("Accept", "application/json");
request.setHeader("Authorization", "Bearer " + token);
// 4. 執行請求
try (CloseableHttpResponse response = client.execute(request)) {
// 5. 處理回應
int status = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, StandardCharsets.UTF_8);
// 處理業務邏輯...
}
// 6. 釋放資源(關鍵!避免連線洩漏)
EntityUtils.consumeQuietly(entity);
}
} finally {
// 應用關閉時統一關閉 client
// client.close();
}
public String doGetWithParams(String url, Mapparams) throws IOException { URIBuilder builder = new URIBuilder(url); params.forEach(builder::addParameter); HttpGet get = new HttpGet(builder.build()); try (CloseableHttpResponse resp = client.execute(get)) { return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); } }
public String postForm(String url, MapformData) throws IOException { HttpPost post = new HttpPost(url); List pairs = new ArrayList<>(); formData.forEach((k, v) -> pairs.add(new BasicNameValuePair(k, v))); post.setEntity(new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8)); try (CloseableHttpResponse resp = client.execute(post)) { return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); } }
public String postJson(String url, String json) throws IOException {
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json;charset=UTF-8");
post.setEntity(new StringEntity(json, ContentType.APPLICATION_JSON));
try (CloseableHttpResponse resp = client.execute(post)) {
return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
}
}
public String uploadFile(String url, File file, String fieldName, MapextraFields) throws IOException { HttpPost post = new HttpPost(url); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.addBinaryBody(fieldName, file, ContentType.DEFAULT_BINARY, file.getName()); if (extraFields != null) { extraFields.forEach((k, v) -> builder.addTextBody(k, v, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8))); } post.setEntity(builder.build()); try (CloseableHttpResponse resp = client.execute(post)) { return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); } }
public CloseableHttpClient createSslClient(String keyStorePath, String keyStorePassword)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream fis = new FileInputStream(keyStorePath)) {
trustStore.load(fis, keyStorePassword.toCharArray());
}
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1.2", "TLSv1.3"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
}
public CloseableHttpClient createOptimizedClient() {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200); // 總連線數上限
cm.setDefaultMaxPerRoute(50); // 單路由連線上限
RequestConfig defaultConfig = RequestConfig.custom()
.setConnectTimeout(5000) // 連線超時 5 秒
.setSocketTimeout(30000) // 讀取超時 30 秒
.setConnectionRequestTimeout(1000) // 從池取連線超時
.setRedirectsEnabled(true)
.build();
return HttpClients.custom()
.setConnectionManager(cm)
.setDefaultRequestConfig(defaultConfig)
.evictIdleConnections(60, TimeUnit.SECONDS) // 定期清理空閒連線
.evictExpiredConnections()
.build();
}
CloseableHttpClient 耗資源,應用生命週期內建立單例或連線池共享finally 或 try-with-resources 中呼叫 EntityUtils.consume(entity) 與 response.close()cm.getTotalStats() 監控連線使用狀況HttpRequestInterceptor/HttpResponseInterceptor 實現統一簽名、日誌、重試邏輯URIBuilder