javax.xml.ws.WebServiceException: Undefined port type: {https://chillyc.info/api}Name
調用 Web Service 客戶端拋出異常,提示找不到對應的 portType 定義。
服務端發布的 WSDL 中 `portType` 名稱與客戶端代碼中 `@WebService` 註解的 `name`/`targetNamespace` 不匹配。JAX-WS 運行時通過 `{namespace}localPart` 唯一標識 portType,任何字符差異 (大小寫、拼寫、命名空間) 都會導致此錯誤。
package myws;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService(
targetNamespace = "https://chillyc.info/api", // 命名空間
name = "HELLO" // portType 名稱 (關鍵!)
)
public interface WebServiceAPI {
String hello(@WebParam(name = "name") String name);
}
package myws;
import javax.jws.*;
import javax.xml.ws.Endpoint;
@WebService(
name = "HELLO", // 必須與接口 name 一致
targetNamespace = "https://chillyc.info/api",
serviceName = "API", // WSDL service 元素 name
portName = "PortName" // WSDL port 元素 name
)
public class WebServiceHolder {
@WebMethod
@WebResult(name = "return")
public String hello(@WebParam(name = "name") String name) {
return "hello" + name;
}
public static void main(String[] args) throws IOException {
Endpoint.publish("https://localhost:80/fake/ws", new WebServiceHolder());
System.in.read();
}
}
<definitions
targetNamespace="https://chillyc.info/api"
name="API"> <-- service name
<portType name="HELLO"> <-- 這裡! 對應 @WebService.name
<operation name="hello">...</operation>
</portType>
<binding name="PortNameBinding" type="tns:HELLO">...</binding>
<service name="API">
<port name="PortName" binding="tns:PortNameBinding">...</port>
</service>
</definitions>
// ❌ 錯誤:QName 使用了 "API" (service name) 而非 "HELLO" (portType name)
WebServiceAPI api = Service.create(
new URL("https://localhost:80/fake/ws?wsdl"),
new QName("https://chillyc.info/api", "API") // 錯誤! 應為 portType 名稱
).getPort(WebServiceAPI.class);
// ✅ 正確:使用 portType 名稱 "HELLO"
WebServiceAPI api = Service.create(
new URL("https://localhost:80/fake/ws?wsdl"),
new QName("https://chillyc.info/api", "HELLO") // 匹配 WSDL portType name
).getPort(WebServiceAPI.class);
| 註解屬性 | WSDL 元素 | 客戶端 QName 參考 | 常見錯誤 |
|---|---|---|---|
| @WebService.name | <portType name="..."> | Service.create(wsdlUrl, QName(ns, portType名)) | 寫成 serviceName 或 portName |
| @WebService.targetNamespace | definitions/@targetNamespace | QName 的 namespace 參數 | 命名空間不一致 (大小寫/尾斜杠) |
| @WebService.serviceName | <service name="..."> | 通常不直接用於 getPort | 誤作為 portType 名稱 |
| @WebService.portName | <port name="..."> | 獲取特定端口時使用 | 誤作為 portType 名稱 |
| @WebParam.name | <part name="..."> | 參數映射 | 與 WSDL message part 不一致 |
"HELLO""HELLO" (必須一致)"https://chillyc.info/api" (兩處一致)new QName("https://chillyc.info/api", "HELLO") 完全匹配上述兩值?wsdl 確認 WSDL 內容已更新# 使用 wsimport 生成客戶端存根 (JDK 自帶)
wsimport -keep -p com.example.client https://localhost:80/fake/ws?wsdl
# 生成的代碼中會包含正確的 QName 常量
// com.example.client.WebServiceAPI_Service.java
public class WebServiceAPI_Service extends Service {
private final static QName WEBSERVICEAPI_QNAME =
new QName("https://chillyc.info/api", "HELLO"); // 自動提取正確 portType
...
}
「Undefined port type」本質是 WSDL 契約與客戶端代碼的命名不一致。核心對應關係:@WebService.name → WSDL portType name → 客戶端 QName localPart。建議採用「WSDL 先行」或「wsimport 生成客戶端」模式,從源頭消除手寫映射錯誤。調試時直接查看 ?wsdl 確認 portType 名稱是最高效定位手段。