WSDL 服务描述
⚠️ 本章为选读内容
本章定位 :理解 WSDL 作为 Web 服务"接口定义语言"的角色——掌握 WSDL 文档的六段结构(types/message/portType/binding/service),建立"WSDL 就是 XML 版 API 文档"的认知。
定义与作用
WSDL (Web Services Description Language)是一种基于 XML 的语言,用于描述 Web 服务:
- 提供了哪些操作 (方法名)
- 每个操作的输入和输出格式 (参数类型、返回类型)
- 如何绑定到具体协议 (SOAP over HTTP?SOAP over SMTP?)
- 服务在哪里 (URL)
WSDL 的角色类似于编程语言的"头文件"或"接口定义"——调用方不需要知道服务内部如何实现,只需要读 WSDL 就知道如何调用。
核心原理:WSDL 六段结构
图解释 :WSDL 的六层结构自底向上——types 定义数据类型(用 XML Schema);message 定义消息结构(引用 types);portType 将消息组合为操作(方法);binding 将抽象操作绑定到具体协议(SOAP);service 指定服务运行在哪个 URL。
语法/结构要点
WSDL 文档结构
| 元素 | 说明 | 必需? |
|---|---|---|
<definitions> | WSDL 文档根元素 | 是 |
<types> | 使用 XSD 定义自定义数据类型 | 否(可用内置类型) |
<message> | 定义操作的消息格式(输入/输出) | 是(至少一个) |
<portType> | 定义操作(方法)集合 | 是 |
<binding> | 将 portType 绑定到具体协议和编码风格 | 是 |
<service> | 服务端点:端口=绑定+URL | 是 |
portType 的操作类型
| 类型 | 说明 | MEP |
|---|---|---|
| one-way | 客户端发消息,服务端不回复 | 单向 |
| request-response | 客户端请求,服务端响应(最常见) | 请求-响应 |
| solicit-response | 服务端主动请求,客户端响应 | 反向请求-响应 |
| notification | 服务端单方面通知 | 单向通知 |
完整示例
场景说明
飞翔科技对外提供一个"订单查询"Web 服务。后端 大翔 写 WSDL,供合作伙伴自动生成客户端代码。
完整 WSDL 文档
OrderService.wsdl :
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
name="OrderService"
targetNamespace="http://www.feixiang.com/order"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.feixiang.com/order">
<!-- 1. types:自定义数据类型 -->
<wsdl:types>
<xsd:schema targetNamespace="http://www.feixiang.com/order">
<xsd:element name="QueryOrderStatusRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="orderId" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="QueryOrderStatusResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="orderId" type="xsd:string"/>
<xsd:element name="status" type="tns:OrderStatus"/>
<xsd:element name="trackingNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="estimatedDelivery" type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="OrderStatus">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="待确认"/>
<xsd:enumeration value="已确认"/>
<xsd:enumeration value="已发货"/>
<xsd:enumeration value="已签收"/>
<xsd:enumeration value="已取消"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</wsdl:types>
<!-- 2. message:定义请求和响应消息 -->
<wsdl:message name="QueryOrderStatusInput">
<wsdl:part name="parameters"
element="tns:QueryOrderStatusRequest"/>
</wsdl:message>
<wsdl:message name="QueryOrderStatusOutput">
<wsdl:part name="parameters"
element="tns:QueryOrderStatusResponse"/>
</wsdl:message>
<!-- 3. portType:定义操作(方法)接口 -->
<wsdl:portType name="OrderPortType">
<wsdl:operation name="QueryOrderStatus">
<wsdl:input message="tns:QueryOrderStatusInput"/>
<wsdl:output message="tns:QueryOrderStatusOutput"/>
</wsdl:operation>
</wsdl:portType>
<!-- 4. binding:绑定到 SOAP -->
<wsdl:binding name="OrderBinding" type="tns:OrderPortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="QueryOrderStatus">
<soap:operation
soapAction="http://www.feixiang.com/order/QueryOrderStatus"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!-- 5. service:服务端点 URL -->
<wsdl:service name="OrderService">
<wsdl:port name="OrderPort" binding="tns:OrderBinding">
<soap:address
location="https://api.feixiang.com/ws/order"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
WSDL 各段对应关系
客户端调用流程:
1. 读取 <service> → 找到 URL:https://api.feixiang.com/ws/order
2. 读取 <binding> → 知道用 SOAP over HTTP,document/literal 风格
3. 读取 <portType> → 知道有 QueryOrderStatus 操作
4. 读取 <message> → 知道输入参数是 orderId(string),返回是 OrderInfo
5. 读取 <types> → 知道 OrderStatus 有 5 个枚举值
操作结果
合作伙伴的开发人员拿到 WSDL 后,可以用工具(如 wsimport、svcutil)自动生成客户端代码:
// Java 自动生成的客户端
OrderService service = new OrderService();
OrderPortType port = service.getOrderPort();
OrderInfo result = port.queryOrderStatus("1001");
System.out.println(result.getStatus()); // "已发货"
易错场景
targetNamespace 不一致
<!-- WSDL 中 -->
targetNamespace="http://www.feixiang.com/order"
<!-- 但 Schema 中 -->
<xsd:schema targetNamespace="http://www.feixiang.com/ORDER"> <!-- 大小写不同!-->
命名空间必须严格一致(包括大小写),否则消息类型无法正确引用。
document/literal vs rpc/encoded 混淆
| 风格 | SOAP Body 中 | 说明 |
|---|---|---|
| document/literal | 数据按 Schema 定义 | 现代主流,WS-I 推荐 |
| rpc/encoded | 数据按 SOAP 编码规则 | 遗留风格,不推荐 |
大多数现代 Web 服务使用 document/literal,避免用 rpc/encoded。
没有更新 WSDL 就修改服务代码
当服务端修改了接口(添加参数、修改返回类型),必须同步更新 WSDL。否则客户端使用的代理类将与服务端不兼容。
面试考点
| 考点 | 参考答案要点 |
|---|---|
| WSDL 文档的六个部分? | definitions(根) → types(数据类型) → message(消息结构) → portType(操作接口) → binding(协议绑定) → service(服务端点URL) |
| WSDL 中 portType 和 binding 的区别? | portType 是抽象的操作定义(与协议无关);binding 将抽象操作绑定到具体协议(SOAP/HTTP)和编码风格 |
| WSDL 和 SOAP 的关系? | WSDL 描述"服务能做什么"和"怎么调";SOAP 是实际调用时的消息格式。WSDL 是说明书,SOAP 是信封 |
| 如何从 WSDL 自动生成客户端代码? | Java:wsimport;.NET:svcutil / WSDL.exe;通过反射机制解析 WSDL XML 结构生成对应的 stub 类 |