項目中需要 Java 調用 .NET 編寫的 WebService,嘗試過 JAX-WS、Axis、CXF 等框架生成客戶端代碼,但因 WSDL 差異、命名空間衝突、複雜類型映射等問題屢屢拋異常。最終採用原生 HttpURLConnection 手工構建 SOAP 消息,繞過框架限制,成功實現互通。下面分享完整工具類代碼與關鍵點解析。
public class QueryDataUtil {
public static String getOpdetailString(String regionId, String regionName, String signalName) throws Exception {
// 1. 構建 SOAP 請求報文
StringBuilder xml = new StringBuilder();
xml.append("");
xml.append("");
xml.append(" ");
xml.append("");
xml.append("")
.append("").append(regionId).append(" ")
.append("").append(regionName).append(" ")
.append("").append(signalName).append(" ")
.append(" ");
xml.append(" ");
// 2. 發送 HTTP POST 請求
String urlString = "https://IP:端口/xxxx?wsdl"; // 替換為真實地址
HttpURLConnection httpConn = null;
OutputStream out = null;
StringBuilder response = new StringBuilder();
try {
// 批次號(可選)
String batchNo = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
System.out.println("開始調用,批次:" + batchNo);
httpConn = (HttpURLConnection) new URL(urlString).openConnection();
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction", "xxx"); // 必須與 .NET 端一致
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setConnectTimeout(10000);
httpConn.setReadTimeout(30000);
httpConn.connect();
out = httpConn.getOutputStream();
out.write(xml.toString().getBytes("UTF-8"));
out.flush();
// 3. 處理響應
int code = httpConn.getResponseCode();
InputStream is = (code == HttpURLConnection.HTTP_OK)
? httpConn.getInputStream() : httpConn.getErrorStream();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
}
System.out.println("響應報文:" + response);
return response.toString();
} finally {
if (out != null) try { out.close(); } catch (IOException ignored) {}
if (httpConn != null) httpConn.disconnect();
}
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 命名空間不匹配 | .NET 默認用 tempuri.org,Java 框架生成的 stub 可能不同 | 手工構建 XML 時完全按 WSDL 定義寫死命名空間 |
| SOAPAction 為空或錯誤 | .NET 要求精確的 SOAPAction Header | 抓包(Wireshark/SoapUI)獲取真實值,填入 setRequestProperty("SOAPAction", "...") |
| 編碼亂碼 | 雙端編碼不一致 | 統一 UTF-8:XML 聲明、HTTP Header、OutputStream/InputStreamReader 都指定 UTF-8 |
| 複雜類型序列化失敗 | 框架無法正確映射 .NET 的 DataSet、ArrayOfXxx 等 | 手工拼裝 XML 完全可控,避開映射層 |
| 超時/連接失敗 | 網絡、防火牆、服務端處理慢 | 設置連接/讀取超時;生產環境建議用連接池 |
sendSoapRequest(url, soapAction, xmlBody),業務層只管組裝 Body。當框架成阻礙時,回歸 HTTP+XML 本質往往是最快的破局之道。這份代碼已在多個 .NET 互操作項目中驗證可用,歡迎根據實際 WSDL 微調命名空間與字段名。