SOAP 协议详解
⚠️ 本章为选读内容
本章定位 :深入 SOAP 消息的内部结构——Envelope/Header/Body 三层模型、故障处理(Fault)、编码规则,理解 SOAP 作为 Web 服务通信协议的核心机制。
定义与作用
SOAP (Simple Object Access Protocol)是一种基于 XML 的轻量级协议,用于在分布式环境中交换结构化信息。它的核心功能:
- 定义消息格式 :服务调用方和提供方之间如何结构化通信
- 独立于传输协议 :虽然通常走 HTTP,但也可运行在 SMTP、TCP 上
- 独立于编程语言 :任何语言只要有 XML 解析器就能发送和接收 SOAP 消息
SOAP 的名字虽然有"Simple",但在实践中它一点也不简单——它的强大之处在于严格的 XML Schema 约束和扩展性。
核心原理:SOAP 消息结构
图解释 :SOAP 消息是"三层信封"结构。Envelope 是总容器;Header 携带元信息(认证令牌、事务 ID)——这里体现了 SOAP 相比 REST 的扩展优势;Body 承载具体的方法调用或返回数据;Fault 是标准化的错误报告。
语法/结构要点
SOAP 1.2 命名空间
soap:Envelope → xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
Envelope 规则
| 规则 | 说明 |
|---|---|
| 必须有 Envelope | 根元素,包含整个 SOAP 消息 |
| 必须有 Body | 承载实际数据 |
| 可选 Header | 扩展信息 |
| EncodingStyle | 可选的 SOAP 编码风格声明 |
| 不允许 DTD | SOAP 消息不能包含 <!DOCTYPE> |
SOAP Fault 字段
| 字段 | 说明 |
|---|---|
faultcode | 错误代码:VersionMismatch、MustUnderstand、Client、Server |
faultstring | 人类可读的错误描述 |
faultactor | 错误发生的节点 |
detail | 应用特定的错误详情 |
完整示例
场景说明
飞翔科技的合作伙伴系统(.NET)需要通过 SOAP 调用飞翔科技的"订单查询"Web 服务。后端 大翔 写了一个简单的 SOAP 服务端。
请求:查询订单状态
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:ord="http://www.feixiang.com/order">
<soap:Header>
<!-- 认证信息在 Header 中传输 -->
<ord:Authentication>
<ord:ApiKey>FX-PARTNER-2026-KEY</ord:ApiKey>
<ord:Timestamp>2026-06-10T14:30:00</ord:Timestamp>
</ord:Authentication>
<!-- 事务追踪 -->
<ord:Transaction>
<ord:TransactionId>TXN-20260610-001</ord:TransactionId>
</ord:Transaction>
</soap:Header>
<soap:Body>
<ord:QueryOrderStatus>
<ord:orderId>1001</ord:orderId>
</ord:QueryOrderStatus>
</soap:Body>
</soap:Envelope>
响应:返回状态信息
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:ord="http://www.feixiang.com/order">
<soap:Body>
<ord:QueryOrderStatusResponse>
<ord:OrderInfo>
<ord:orderId>1001</ord:orderId>
<ord:customer>乐途伙伴公司</ord:customer>
<ord:status>已发货</ord:status>
<ord:trackingNumber>SF1234567890</ord:trackingNumber>
<ord:estimatedDelivery>2026-06-12</ord:estimatedDelivery>
<ord:items>
<ord:item>
<ord:product>工单模块</ord:product>
<ord:quantity>10</ord:quantity>
</ord:item>
</ord:items>
</ord:OrderInfo>
</ord:QueryOrderStatusResponse>
</soap:Body>
</soap:Envelope>
错误响应:SOAP Fault(订单不存在)
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="zh">订单 ID 9999 不存在</soap:Text>
</soap:Reason>
<soap:Detail>
<ord:OrderFault xmlns:ord="http://www.feixiang.com/order">
<ord:ErrorCode>ORDER_NOT_FOUND</ord:ErrorCode>
<ord:OrderId>9999</ord:OrderId>
</ord:OrderFault>
</soap:Detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
操作结果
| 场景 | HTTP 状态码 | SOAP 消息内容 |
|---|---|---|
| 成功查询 | 200 OK | Body 中包含 QueryOrderStatusResponse |
| 订单不存在 | 200 OK | Body 中包含 Fault(注意:HTTP 仍是 200!) |
| 认证失败 | 200 OK 或 500 | Body 中包含 Fault |
| 格式错误 | 200 OK 或 500 | Body 中包含 VersionMismatch Fault |
关键:SOAP 错误通过 Fault 元素传递,而非 HTTP 状态码。即使业务逻辑出错,HTTP 状态码通常仍是 200。
易错场景
用 HTTP 状态码判断业务成功/失败
// 错误:检查 HTTP status
if (xhr.status === 200) {
// 假设成功——但 SOAP Fault 也在 200 里!
}
SOAP 的 Fault 通常在 HTTP 200 里返回。必须检查响应体中是否有 <soap:Fault> 元素,而非仅看 HTTP 状态码。
忘记声明命名空间前缀
<soap:Envelope>
<soap:Body>
<QueryOrderStatus> <!-- 错误:应该带命名空间前缀 ord: -->
SOAP Body 中的业务元素必须有正确的命名空间前缀,否则服务端无法路由到正确的方法。
SOAP 1.1 和 1.2 的混乱
| 特性 | SOAP 1.1 | SOAP 1.2 |
|---|---|---|
| 命名空间 | http://schemas.xmlsoap.org/soap/envelope/ | http://www.w3.org/2003/05/soap-envelope |
| Fault 结构 | faultcode / faultstring | Code / Reason 子元素 |
| HTTP 绑定 | 仅 HTTP POST | HTTP POST + GET |
客户端的 SOAP 版本必须与服务端一致,否则服务端可能返回 VersionMismatch。
面试考点
| 考点 | 参考答案要点 |
|---|---|
| SOAP 消息的三层结构? | Envelope(根容器)→ Header(可选元信息:认证/事务/路由)→ Body(必需业务数据或 Fault) |
| SOAP Header 的典型用途? | 认证令牌、分布式事务 ID、消息路由指令、数字签名 |
| SOAP Fault 的作用? | 标准化的错误报告,包含 faultcode(错误类型)、faultstring(人类可读描述)、detail(应用特定详情) |
| 为什么 SOAP 比 REST 更"重"? | SOAP 需要完整的 XML Envelope 包装、WSDL 接口定义、严格的 XML Schema 验证;REST 直接使用 HTTP 动词和简洁的 JSON |