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

Java 獲取 HTTP/HTTPS 接口 JSON 數據完整指南:原生實現與最佳實踐

     編輯:Java 相關知識

核心課題

調用 REST API 獲取 JSON 數據是微服務架構常見需求。HTTPS 需處理 SSL 證書信任、主機名驗證;HTTP 需處理連接池、超時、重試。本文提供生產級原生實現方案。

HTTP 請求實現

public class HttpClientUtil {
    private static final int CONNECT_TIMEOUT = 5000;
    private static final int READ_TIMEOUT = 10000;

    public static JSONObject httpRequest(String url, String method) throws IOException {
        return httpRequest(url, method, null);
    }

    public static JSONObject httpRequest(String url, String method, String body) throws IOException {
        HttpURLConnection conn = createConnection(url);
        conn.setRequestMethod(method);
        conn.setConnectTimeout(CONNECT_TIMEOUT);
        conn.setReadTimeout(READ_TIMEOUT);
        conn.setRequestProperty("Accept", "application/json");
        
        if (body != null) {
            conn.setDoOutput(true);
            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            try (OutputStream os = conn.getOutputStream()) {
                os.write(body.getBytes(StandardCharsets.UTF_8));
            }
        }

        return parseResponse(conn);
    }

    private static HttpURLConnection createConnection(String urlString) throws IOException {
        URL url = new URL(urlString);
        return (HttpURLConnection) url.openConnection();
    }

    private static JSONObject parseResponse(HttpURLConnection conn) throws IOException {
        int status = conn.getResponseCode();
        InputStream is = status >= 400 ? conn.getErrorStream() : conn.getInputStream();
        
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(is, StandardCharsets.UTF_8))) {
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = br.readLine()) != null) sb.append(line);
            return new JSONObject(sb.toString());
        } finally {
            conn.disconnect();
        }
    }
}

HTTPS 請求實現 (信任所有證書 - 僅測試環境)

public class HttpsClientUtil {
    public static JSONObject httpsRequest(String url, String method, String body) 
            throws IOException, GeneralSecurityException {
        
        // 1. 創建信任所有證書的 TrustManager
        TrustManager[] trustAll = new TrustManager[]{
            new X509ExtendedTrustManager() {
                @Override public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                @Override public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
            }
        };

        // 2. 初始化 SSLContext
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAll, new SecureRandom());

        // 3. 創建連接並設置 SocketFactory
        URL urlObj = new URL(url);
        HttpsURLConnection conn = (HttpsURLConnection) urlObj.openConnection();
        conn.setSSLSocketFactory(sslContext.getSocketFactory());
        
        // 4. 禁用主機名驗證 (僅測試)
        conn.setHostnameVerifier((hostname, session) -> true);

        // 後續設置同 HTTP
        conn.setRequestMethod(method);
        conn.setConnectTimeout(5000);
        conn.setReadTimeout(10000);
        // ... 發送請求體、解析響應 (同上)
        
        return parseResponse(conn);
    }
}

生產環境 HTTPS 安全加固

  1. 證書驗證:生產環境絕不可信任所有證書。應將服務端 CA 證書導入 JDK truststore 或自定義 KeyStore:
// 正確做法:加載指定信任庫
KeyStore trustStore = KeyStore.getInstance("JKS");
try (InputStream is = new FileInputStream("truststore.jks")) {
    trustStore.load(is, "changeit".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
  1. 主機名驗證:保留默認驗證,或實現自定義 HostnameVerifier 校驗 CN/SAN
  2. 協議版本:指定 TLS 1.2+,禁用 SSLv3、TLS 1.0/1.1
  3. 連接復用:啟用 HTTP Keep-Alive,配置連接池 (建議使用 Apache HttpClient/OkHttp)

現代替代方案推薦

庫特點適用場景
Apache HttpClient 4.5+連接池、重試、攔截器、完整 HTTP 協議支持企業級應用、高併發
OkHttp 3.x+連接池、HTTP/2、透明 GZIP、現代 APIAndroid、微服務調用
Spring RestTemplate / WebClientSpring 生態集成、聲明式配置、響應式Spring Boot 應用
JDK 11+ HttpClient原生、支持 HTTP/2、WebSocket、CompletableFuture無第三方依賴項目

JDK 11 HttpClient 示例 (推薦無依賴項目)

HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(5))
    .build();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.example.com/data"))
    .header("Accept", "application/json")
    .GET()
    .build();

CompletableFuture<String> future = client.sendAsync(request, BodyHandlers.ofString())
    .thenApply(HttpResponse::body);

String json = future.join(); // 或異步處理
JSONObject data = new JSONObject(json);

常見問題排查

  • PKIX path building failed:服務端證書不受信,導入 CA 到 truststore 或使用自定義 TrustManager
  • Hostname verification failed:證書 CN 不匹配域名,檢查證書 SAN 或實現驗證邏輯
  • Read timed out:增加讀取超時,檢查網絡/防火牆/服務端性能
  • 中文亂碼:統一指定 UTF-8,檢查響應 Headers Content-Type charset

總結

原生 HttpURLConnection 適合簡單場景,生產環境強烈建議使用成熟 HTTP 客戶端庫。HTTPS 核心在於正確配置信任庫與主機名驗證,切勿在生產代碼中禁用安全檢查。掌握 JDK 11+ 原生 HttpClient 可在零依賴下獲得現代異步 HTTP 能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved