早期分散式系統採用 DCOM、CORBA (RCP) 進行遠端呼叫,但這些協議在網際網路環境面臨防火牆阻擋、跨平台困難、安全性複雜等問題。SOAP (Simple Object Access Protocol) 基於 XML + HTTP,穿透防火牆、跨語言跨平台、人類可讀,成為 Web Services 的基石協議。
Envelope → Header (可選) + Body (必選,含方法呼叫/回應/錯誤)
| 元件 | 版本 | 來源 |
|---|---|---|
| JDK | 1.4.1+ | Sun/Oracle |
| Servlet 容器 | Tomcat 4.1.29+ | Apache Jakarta |
| Apache SOAP | 2.3.1 | Apache XML Project |
| JavaMail | 1.3.1 | Sun (MTOM/附件支援) |
| JAF | 1.0.2 | Sun (JavaMail 依賴) |
| Xerces | 2.6.0 | Apache XML Parser |
bin/setclasspath.bat)
set CATALINA_HOME=C:\Tomcat4.1.29
set CLASSPATH=%JAVA_HOME%\lib\tools.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\soap-2.3.1\lib\soap.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\javamail-1.3.1\mail.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\jaf-1.0.2\activation.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\xerces-2_6_0\xercesImpl.jar
set CLASSPATH=%CLASSPATH%;%JAVA_HOME%\xerces-2_6_0\xml-apis.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\common\lib\servlet.jar
// HelloWorld/SOAPService.java
package HelloWorld;
public class SOAPService {
public String sayHi(String x) {
return "Hello my friend, " + x + "! Glad to see you!";
}
}
# 編譯
javac HelloWorld/SOAPService.java
# 確保 HelloWorld 目錄在 CLASSPATH 中
https://localhost:8080/soap/| 欄位 | 值 | 說明 |
|---|---|---|
| ID | urn:HelloWorld_SOAPService | Service 唯一識別碼,Client 端呼叫時使用 |
| Scope | Application | 生命週期:Request/Session/Application |
| Methods | sayHi | 公開方法列表,逗號分隔 |
| Provider Type | java | Java 類別提供者 |
| Java Provider - Provider Class | HelloWorld.SOAPService | 完整類別名稱 |
| Java Provider - Static? | No | 非靜態方法,每次請求新建實例 |
// HelloWorldClient.java
import java.net.URL;
import java.util.Vector;
import org.apache.soap.*;
import org.apache.soap.rpc.*;
public class HelloWorldClient {
public static void main(String[] args) throws Exception {
String endpoint = "https://localhost:8080/soap/servlet/rpcrouter";
String serviceURN = "urn:HelloWorld_SOAPService";
String methodName = "sayHi";
String paramName = "ourName";
String paramValue = "Superman";
Call call = new Call();
call.setTargetObjectURI(serviceURN);
call.setMethodName(methodName);
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); // SOAP 編碼風格
Vector params = new Vector();
params.addElement(new Parameter(paramName, String.class, paramValue, null));
call.setParams(params);
System.out.print("呼叫 " + serviceURN + "." + methodName + "(" + paramValue + ") → ");
Response response = call.invoke(new URL(endpoint), "");
if (response.generatedFault()) {
Fault fault = response.getFault();
System.out.println("失敗! Code=" + fault.getFaultCode() + ", Msg=" + fault.getFaultString());
} else {
Parameter result = response.getReturnValue();
System.out.println("成功: " + result.getValue());
}
}
}
javac HelloWorldClient.java
java HelloWorldClient
呼叫 urn:HelloWorld_SOAPService.sayHi(Superman) → 成功: Hello my friend, Superman! Glad to see you!
Superman
Hello my friend, Superman! Glad to see you!
SOAP 本身不描述服務介面。WSDL (Web Services Description Language) 定義服務端點、操作、訊息格式、綁定協議。工具可從 WSDL 自動生成 Client Stub / Server Skeleton。
@WebService, @WebMethod),內建於 JDK 6+,支援 MTOM、WS-* 標準現代微服務傾向 REST + JSON:語義清晰 (HTTP 動詞)、輕量、瀏覽器原生支援、易於快取。但 SOAP 在企業級強契約、WS-Security、分散式交易 (WS-AtomicTransaction)、非 HTTP 傳輸等場景仍具不可替代性。
| 問題 | 原因 | 解決 |
|---|---|---|
| ClassNotFoundException: SOAPService | CLASSPATH 未包含 Service 類別目錄 | 確認 Tomcat 啟動 CLASSPATH 或放入 WEB-INF/classes |
| Fault: "Service not found" | URN 不匹配或未部署 | Admin Tool List 確認 ID 拼寫 |
| 連線逾時/拒絕 | Tomcat 未啟動或端口錯誤 | 驗證 https://localhost:8080/soap/ 可訪問 |
| 中文亂碼 | 編碼不一致 | 確保 Client/Server/XML 皆用 UTF-8,JVM 參數 -Dfile.encoding=UTF-8 |
SOAP 以 XML + HTTP 實現了跨平台、穿透防火牆的遠端呼叫標準。雖然現代趨勢轉向 REST,但理解 SOAP 的 Envelope 結構、RPC 路由機制、WSDL 契約、安全擴展,對維護既有企業系統、對接金融/電信/政府等強契約介面仍具關鍵價值。本文從環境建置到 HelloWorld 完整落地,提供可直接執行的實戰範本。