首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Apache HttpClient 4.x 完整使用指南:從基礎請求到 SSL、檔案上傳進階實戰

     編輯:Java 相關知識

前言

Apache HttpClient 是 Java 生態系中最廣泛使用的 HTTP 客端端庫,相較於 JDK 內建的 HttpURLConnection,它提供了更豐富的 API、連線池管理、自動重試、Cookie 管理、攔截器機制等企業級功能。本文基於 HttpClient 4.3+ 版本,系統性介紹核心用法與實戰場景。

核心架構組件

組件職責
CloseableHttpClientHTTP 客戶端主介面,執行請求、管理連線池
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();
}

實戰場景完整範例

1. GET 請求帶查詢參數

public String doGetWithParams(String url, Map params) 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);
    }
}

2. POST 表單提交

public String postForm(String url, Map formData) 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);
    }
}

3. POST JSON 資料

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);
    }
}

4. 檔案上傳

public String uploadFile(String url, File file, String fieldName, Map extraFields) 
        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);
    }
}

5. SSL/HTTPS 信任自簽憑證

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();
}

最佳實務總結

  1. 客戶端複用:CloseableHttpClient 耗資源,應用生命週期內建立單例或連線池共享
  2. 資源釋放:務必在 finally 或 try-with-resources 中呼叫 EntityUtils.consume(entity) 與 response.close()
  3. 超時設定:生產環境必須設定連線/讀取/取連線三類超時,防止阻塞
  4. 連線池監控:定期檢視 cm.getTotalStats() 監控連線使用狀況
  5. 攔截器擴展:實作 HttpRequestInterceptor/HttpResponseInterceptor 實現統一簽名、日誌、重試邏輯

常見坑點避雷

  • ❌ 每次請求 `new HttpClients.createDefault()` → 連線無法複用、端口耗盡
  • ❌ 忘記 `EntityUtils.consume()` → 連線無法回收池中、洩漏
  • ❌ 無超時設定 → 下游服務掛起導致調用方線程耗盡
  • ❌ 手動拼接 URL 參數 → 編碼錯誤、安全風險,請用 URIBuilder
  • ❌ 信任所有憑證 (`TrustAllStrategy`) → 中間人攻擊風險,生產嚴禁
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved