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

Java HttpClient 4.x 實現 POST 請求完整實戰:JSON 傳輸、超時控制、Jar 衝突排查

     編輯:Java 相關知識

核心代碼:發送 JSON POST 請求


import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import net.sf.json.JSONObject;
import java.nio.charset.Charset;
import java.util.UUID;

public class HttpClientUtil {
    public static boolean httpPostWithJson(JSONObject jsonObj, String url, String appId) {
        HttpPost post = null;
        try {
            HttpClient httpClient = new DefaultHttpClient();
            
            // 1. 設置連接/讀取超時(毫秒)
            httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);
            httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
            
            post = new HttpPost(url);
            
            // 2. 構造請求頭
            post.setHeader("Content-type", "application/json; charset=utf-8");
            post.setHeader("Connection", "Close");
            post.setHeader("SessionId", generateSessionId());
            post.setHeader("appid", appId);
            
            // 3. 構建 JSON 請求體
            StringEntity entity = new StringEntity(jsonObj.toString(), Charset.forName("UTF-8"));
            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            post.setEntity(entity);
            
            // 4. 執行請求
            HttpResponse response = httpClient.execute(post);
            int statusCode = response.getStatusLine().getStatusCode();
            
            if (statusCode != HttpStatus.SC_OK) {
                logError("HTTP 錯誤狀態碼: " + statusCode);
                return false;
            }
            
            // 5. 解析響應頭業務碼
            int retCode = 0;
            String sessionId = "";
            for (Header header : response.getAllHeaders()) {
                if ("retcode".equals(header.getName())) 
                    retCode = Integer.parseInt(header.getValue());
                if ("SessionId".equals(header.getName())) 
                    sessionId = header.getValue();
            }
            
            if (retCode != ErrorCodeHelper.IAS_SUCCESS) {
                logError("業務錯誤碼: " + retCode + ", SessionId: " + sessionId);
                return false;
            }
            return true;
            
        } catch (Exception e) {
            logError("請求異常: " + e.getMessage());
            return false;
        } finally {
            // 6. 釋放連接資源
            if (post != null) {
                try {
                    post.releaseConnection();
                    Thread.sleep(500); // 避免連接過於頻繁
                } catch (InterruptedException ignored) {}
            }
        }
    }
    
    // 生成簡短 SessionId
    private static String generateSessionId() {
        UUID uuid = UUID.randomUUID();
        String s = uuid.toString();
        return s.substring(0,8) + s.substring(9,13) + s.substring(14,18) + s.substring(19,23) + s.substring(24);
    }
}

關鍵技術點詳解

1. 超時設置的兩個關鍵參數

  • CONNECTION_TIMEOUT:建立 TCP 連接的最長等待時間
  • SO_TIMEOUT:讀取數據(Socket read)的最長等待時間
  • 生產環境建議:連接 2-5s,讀取 5-30s,視業務而定

2. JSON 實體構建最佳實踐

  • 顯式指定 Charset.forName("UTF-8") 避免中文亂碼
  • 同時設置 Content-Type 和 Content-Encoding
  • 使用 StringEntity 而非 ByteArrayEntity,自動處理編碼

3. 響應頭業務碼解析模式

許多內部 RPC 協議將業務狀態碼放在 Header 中(如 retcode、SessionId),而非 Body,需遍歷 response.getAllHeaders() 獲取。

生產環境血案:Hadoop 環境下 NoSuchFieldError: INSTANCE

現象


java.lang.NoSuchFieldError: INSTANCE
    at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(...)

根因分析

  • Hadoop 運行時優先加載自身 lib 目錄下的 JAR(如 httpclient-4.2.5.jar)
  • 應用打包的 JAR(如 httpclient-4.4.1.jar)被忽略
  • 版本不一致導致類結構差異,字段 INSTANCE 在 4.2.5 中不存在

解決方案

  1. 統一版本:將項目 pom.xml 依賴降級/升級至 Hadoop 環境一致版本(如 4.2.5)
  2. Shade 重定向包名:使用 maven-shade-plugin 將依賴重定向到私有包名,避免衝突
  3. ClassLoader 隔離:自定義 ClassLoader 優先加載應用 JAR(複雜,慎用)

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.2.5</version> <!-- 與 Hadoop 環境一致 -->
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.2.5</version>
</dependency>

HttpClient 4.x vs 5.x 遷移提示

項目4.x (Legacy)5.x (Modern)
客戶端創建new DefaultHttpClient()HttpClients.createDefault()
請求構建new HttpPost(url)HttpPost.METHOD_NAME, URI.create(url)
執行方式client.execute(request)client.execute(request, responseHandler)
連接管理PoolingClientConnectionManagerPoolingHttpClientConnectionManager
異步支持無CloseableHttpAsyncClient

新項目建議直接使用 5.x,API 更現代、支持響應式、連接池管理更完善。

總結

HttpClient 實現 POST 請求核心流程:創建客戶端 → 設置超時 → 構造請求頭/體 → 執行 → 解析響應 → 釋放資源。生產環境務必關注:

  • 超時設置防止線程阻塞耗盡
  • 連接釋放避免連接泄漏
  • 依賴版本一致性防止 Jar 衝突
  • 異常處理與日誌記錄便於排查
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved