每次請求 HttpClients.createDefault() 建立新 Client 極其低效:TCP 連線建立/銷毀、TLS 握手、DNS 解析重複開銷。HttpClient 內建 連線池 解決此問題。
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200); // 整個池最大連線數
cm.setDefaultMaxPerRoute(50); // 單一路由預設最大連線
// 特定站點調整
cm.setMaxPerRoute(new HttpRoute(new HttpHost("api.example.com")), 100);
CloseableHttpClient client = HttpClients.custom()
.setConnectionManager(cm)
.setConnectionManagerShared(true) // 共享連線管理器
.build();
CloseableHttpClient 為**執行緒安全**,單例注入全局複用:
public class HttpUtil {
private static final CloseableHttpClient HTTP_CLIENT;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(50);
HTTP_CLIENT = HttpClients.custom().setConnectionManager(cm).build();
}
public static String get(String url) throws IOException {
try (CloseableHttpResponse resp = HTTP_CLIENT.execute(new HttpGet(url))) {
return EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8);
}
}
}
依賴 fluent-hc 模組(內建連線池,預設 maxTotal=200, maxPerRoute=100):
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.13</version>
</dependency>
String html = Request.Get("https://api.example.com")
.connectTimeout(1000)
.socketTimeout(3000)
.addHeader("Accept", "application/json")
.execute()
.returnContent()
.asString(StandardCharsets.UTF_8);
| 參數 | 建議值 | 說明 |
|---|---|---|
| MaxTotal | 200-500 | 視機器檔案描述符限制調整 |
| MaxPerRoute | 20-100 | 單域名並發上限,防單點壓垮 |
| ValidateAfterInactivity | 2000ms | 閒置連線重用前驗證,避免斷連 |
| ConnectionRequestTimeout | 1000ms | 從池獲取連線超時,防飢餓 |
| Keep-Alive 策略 | 自訂 | 依伺服器 Header 動態決定存活時間 |
應用關閉時呼叫 cm.close() 或 client.close() 釋放所有連線。
掌握連線池與 Fluent API,輕鬆構建高吞吐、資源可控的 HTTP 客戶端。