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

HttpClient 發起 HTTPS 請求完全指南:信任所有證書、超時配置、資源釋放

     編輯:Java 綜合教學

HttpClient 發起 HTTPS 請求完全指南:信任所有證書、超時配置、資源釋放

生產環境常需調用第三方 HTTPS 接口。Apache HttpClient 4.5+ 提供靈活的 SSL 上下文構建器,本文提供生產就緒的工具類代碼,涵蓋:信任所有證書(測試環境)、連接/讀取/請求三層超時、響應實體消費、連接管理器釋放、異常處理與日志記錄。

核心工具類代碼

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.X509Certificate;

public class HttpsClientUtil {

    private static final int TIMEOUT_MS = 5000;
    private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom()
            .setConnectTimeout(TIMEOUT_MS)
            .setSocketTimeout(TIMEOUT_MS)
            .setConnectionRequestTimeout(TIMEOUT_MS)
            .build();

    /** 獲取 HTTPS 響應文本(信任所有證書,僅測試環境使用) */
    public static String getSSL(String url, String responseCharset) throws IOException {
        CloseableHttpClient httpClient = createTrustAllClient();
        CloseableHttpResponse response = null;
        try {
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(REQUEST_CONFIG);
            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String content = EntityUtils.toString(entity, responseCharset);
                EntityUtils.consume(entity); // 釋放連接回池
                return content;
            }
            return null;
        } catch (IOException e) {
            // log.error("HTTPS request failed: {}", url, e);
            throw e;
        } finally {
            closeQuietly(response);
            closeQuietly(httpClient);
        }
    }

    /** 構建信任所有證書的 HttpClient(生產環境請載入具體信任庫) */
    private static CloseableHttpClient createTrustAllClient() {
        try {
            SSLContext sslContext = new SSLContextBuilder()
                    .loadTrustMaterial(null, (TrustStrategy) (X509Certificate[] chain, String authType) -> true)
                    .build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .setDefaultRequestConfig(REQUEST_CONFIG)
                    .build();
        } catch (Exception e) {
            // log.warn("SSL context init failed, fallback to default", e);
            return HttpClients.createDefault();
        }
    }

    private static void closeQuietly(AutoCloseable closeable) {
        if (closeable != null) {
            try { closeable.close(); } catch (Exception ignored) {}
        }
    }

    // POST 範例
    public static String postSSL(String url, String jsonBody, String charset) throws IOException {
        CloseableHttpClient client = createTrustAllClient();
        CloseableHttpResponse resp = null;
        try {
            HttpPost post = new HttpPost(url);
            post.setConfig(REQUEST_CONFIG);
            post.setEntity(new StringEntity(jsonBody, ContentType.APPLICATION_JSON));
            resp = client.execute(post);
            HttpEntity entity = resp.getEntity();
            return entity != null ? EntityUtils.toString(entity, charset) : null;
        } finally {
            closeQuietly(resp);
            closeQuietly(client);
        }
    }
}

關鍵配置解析

配置項含義建議值
setConnectTimeout建立 TCP 連接超時5000ms
setSocketTimeout讀取數據超時 (SO_TIMEOUT)5000ms
setConnectionRequestTimeout從連接池獲取連接超時5000ms
TrustStrategy → true跳過證書驗證(自簽/測試環境)僅測試環境
EntityUtils.consume()確保實體流讀完,連接釋放回池必須調用

生產環境安全加固(必讀)

⚠️ 切勿在生產環境使用「信任所有證書」! 應採用以下任一方式:
  1. 載入 CA 信任庫:
    SSLContextBuilder().loadTrustMaterial(new File("truststore.jks"), "changeit".toCharArray())
  2. 指定主機名驗證器:
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslContext, new String[]{"TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
  3. 憑證釘選:儲存目標公鑰指紋,驗證時比對

Maven 依賴

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.14</version> <!-- 或 4.5.x 最新 -->
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.14</version>
</dependency>

常見坑點與排查

  • PKIX path building failed:目標證書非受信 CA 簽發 → 導入目標證書鏈至 JVM cacerts 或自定義 TrustStore
  • Connection pool shut down:HttpClient 為單例複用,勿在方法內重複創建/關閉
  • 響應體未消費導致連接洩漏:必須調用 EntityUtils.consume(entity) 或完整讀取流
  • 超時設置不生效:確保 RequestConfig 同時應用於 Client 默認與 Request 級別

進階:連接池優化配置

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);           // 最大連接數
cm.setDefaultMaxPerRoute(50);  // 每路由最大連接
cm.setValidateAfterInactivity(2000); // 空閒 2s 後驗證有效性

CloseableHttpClient client = HttpClients.custom()
        .setConnectionManager(cm)
        .setDefaultRequestConfig(REQUEST_CONFIG)
        .evictIdleConnections(30, TimeUnit.SECONDS) // 定時清理空閒
        .build();
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved