SOAP 教程

SOAP 教程

SOAP(Simple Object Access Protocol,简单对象访问协议)是 W3C 制定的基于 XML 的消息交换协议,用于分布式环境中应用程序之间的通信,是传统 Web 服务(WS-*)的核心标准。

核心特点

  • 基于 XML:消息格式标准,跨语言跨平台
  • 独立传输:可运行于 HTTP、SMTP、TCP 等协议之上
  • 强类型:通过 WSDL 描述接口契约
  • 安全标准成熟:WS-Security 支持加密与签名
  • 状态无关:无状态协议,每个消息独立处理

消息结构

<soap:Envelope>      <!-- 根元素 -->
  <soap:Header>      <!-- 可选,元数据 -->
  </soap:Header>
  <soap:Body>       <!-- 必选,实际数据 -->
  </soap:Body>
</soap:Envelope>

学习路线

  1. 简介与语法
  2. Envelope / Header / Body / Fault 元素
  3. HTTP Binding
  4. 实例、总结

SOAP 简介

SOAP 简介

1. 历史背景

1998 年  由 Microsoft、DevelopMentor 提出
2000 年  W3C 接管,成为 Web 服务标准
2003 年  SOAP 1.2 成为 W3C 推荐标准
2007 年  SOAP 1.2 第二版

# 注:SOAP 1.2 后不再扩展缩写含义

2. 为什么用 SOAP

  • 企业级应用集成(异构系统通信)
  • 严格的接口契约(WSDL)
  • 安全与事务需求(WS-Security、WS-Transaction)
  • 语言无关(Java/C#/Python 互通)

3. SOAP vs REST

对比项SOAPREST
数据格式XMLJSON/XML
协议HTTP/SMTP/TCPHTTP
接口契约WSDL(强)OpenAPI(可选)
学习曲线陡平缓
性能消息大,慢轻量,快
适用企业金融级互联网应用

4. 典型场景

  • 银行、支付系统集成
  • 电信运营商 BSS/OSS
  • 传统 ERP/CRM 对接
  • 跨企业 B2B 交易

SOAP 语法

SOAP 语法

1. 基本语法规则

# SOAP 消息必须使用 XML 编码
# 必须使用 SOAP Envelope 命名空间
# 必须使用 XML 编码(不能省略 Envelope/Body)
# 不能包含 DTD 或 XML 处理指令

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
  <soap:Body>
    <m:GetPrice xmlns:m="http://example.com/ws">
      <m:Item>Apples</m:Item>
    </m:GetPrice>
  </soap:Body>
</soap:Envelope>

2. 命名空间

# SOAP 1.1
http://schemas.xmlsoap.org/soap/envelope/

# SOAP 1.2
http://www.w3.org/2003/05/soap-envelope

# 编码规范
SOAP 1.1: http://schemas.xmlsoap.org/soap/encoding/
SOAP 1.2: http://www.w3.org/2003/05/soap-encoding

# 业务命名空间(自定义)
xmlns:m="http://example.com/ws"

3. 结构要求

# Envelope
# - 根元素,标识 SOAP 消息
# - 必须包含 Body

# Header(可选)
# - 携带认证、事务等元信息

# Body(必选)
# - 包含实际请求/响应数据
# - 或包含 Fault(错误)

# Fault(错误时出现)
# - 位于 Body 内
# - 描述错误信息

4. 编码风格

# encodingStyle 指定编码规则
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding"

# 数组编码
<tns:numbers soap:arrayType="xsd:int[3]">
  <tns:int>1</tns:int>
  <tns:int>2</tns:int>
  <tns:int>3</tns:int>
</tns:numbers>

SOAP Envelope 元素

SOAP Envelope 元素

1. Envelope 定义

# Envelope 是 SOAP 消息的根元素
# 标识文档为 SOAP 消息

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  ...
</soap:Envelope>

2. 命名空间要求

# 必须正确使用命名空间

# SOAP 1.1
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

# SOAP 1.2
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope">

# 错误命名空间会报 VersionMismatch 错误

3. 结构规则

# 结构
Envelope
├── Header(可选,可多个)
└── Body(必须,且只一个)

# 规则
- Header 必须在 Body 之前
- Body 最多一个
- Envelope 内容不能包含额外顶层元素

4. 完整示例

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  xmlns:m="http://example.com/order">

  <soap:Header>
    <m:Auth>
      <m:Token>abc123</m:Token>
    </m:Auth>
  </soap:Header>

  <soap:Body>
    <m:CreateOrder>
      <m:Item>Laptop</m:Item>
      <m:Quantity>2</m:Quantity>
    </m:CreateOrder>
  </soap:Body>
</soap:Envelope>

SOAP Header 元素

SOAP Header 元素

1. Header 作用

# Header 是可选的,用于携带消息的"附加信息"
# 常见用途:
- 认证信息(Token、用户名密码)
- 事务标识
- 消息路由信息
- 优先级
- 版本信息

2. 基本用法

<soap:Header>
  <m:Auth xmlns:m="http://example.com/auth">
    <m:Username>admin</m:Username>
    <m:Password>secret</m:Password>
  </m:Auth>
</soap:Header>

3. Header 属性

# mustUnderstand:接收方必须处理
<m:Auth soap:mustUnderstand="1">
# 接收方不理解该 header 时报 Fault

# actor(SOAP 1.1)/role(SOAP 1.2)
# 指定处理该 header 的节点
<m:Log soap:actor="http://example.com/log">

# relay(SOAP 1.2)
# 是否可传递给下游节点
<m:Info soap:relay="true">

4. 认证 Header 示例

<soap:Header>
  <wsse:Security
    xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    <wsse:UsernameToken>
      <wsse:Username>api_user</wsse:Username>
      <wsse:Password Type="PasswordText">pass123</wsse:Password>
    </wsse:UsernameToken>
  </wsse:Security>
</soap:Header>

5. 事务 Header 示例

<soap:Header>
  <t:Transaction
    xmlns:t="http://example.com/transaction"
    soap:mustUnderstand="1">
    <t:TransactionID>TX-20260818-001</t:TransactionID>
  </t:Transaction>
</soap:Header>

SOAP Body 元素

SOAP Body 元素

1. Body 作用

# Body 是必选元素,包含消息的实际内容
# - 请求:调用的方法及其参数
# - 响应:方法返回的数据
# - 错误:Fault 元素

2. 请求示例

<soap:Body>
  <m:GetPrice xmlns:m="http://example.com/ws">
    <m:Item>Apples</m:Item>
  </m:GetPrice>
</soap:Body>

3. 响应示例

<soap:Body>
  <m:GetPriceResponse xmlns:m="http://example.com/ws">
    <m:Price>1.50</m:Price>
    <m:Currency>USD</m:Currency>
  </m:GetPriceResponse>
</soap:Body>

4. 复杂数据类型

<soap:Body>
  <m:CreateOrder xmlns:m="http://example.com/order">
    <m:Order>
      <m:Customer>
        <m:Name>张三</m:Name>
        <m:Email>zhang@example.com</m:Email>
      </m:Customer>
      <m:Items>
        <m:Item>
          <m:Product>Laptop</m:Product>
          <m:Qty>1</m:Qty>
        </m:Item>
        <m:Item>
          <m:Product>Mouse</m:Product>
          <m:Qty>2</m:Qty>
        </m:Item>
      </m:Items>
    </m:Order>
  </m:CreateOrder>
</soap:Body>

5. Body 规则

# 必须存在且只有一个
# 命名空间必须正确
# 内容为业务数据或 Fault
# 不能包含属性(除命名空间声明)

SOAP Fault 元素

SOAP Fault 元素

1. Fault 作用

# 当请求处理失败时,Body 中包含 Fault 元素
# 用于向发送方报告错误信息

2. Fault 结构(SOAP 1.2)

<soap:Body>
  <soap:Fault>
    <soap:Code>
      <soap:Value>soap:Sender</soap:Value>
      <soap:Subcode>
        <soap:Value>m:InvalidItem</soap:Value>
      </soap:Subcode>
    </soap:Code>
    <soap:Reason>
      <soap:Text xml:lang="en">Invalid item name</soap:Text>
      <soap:Text xml:lang="zh">无效的商品名称</soap:Text>
    </soap:Reason>
    <soap:Node>http://example.com/server</soap:Node>
    <soap:Role>http://example.com/processor</soap:Role>
    <soap:Detail>
      <m:ErrorInfo xmlns:m="http://example.com">
        <m:Code>E1001</m:Code>
      </m:ErrorInfo>
    </soap:Detail>
  </soap:Fault>
</soap:Body>

3. Fault 结构(SOAP 1.1)

<soap:Fault>
  <faultcode>soap:Client</faultcode>
  <faultstring>无效的参数</faultstring>
  <faultactor>http://example.com/server</faultactor>
  <detail>
    <m:Error xmlns:m="http://example.com">
      详细信息
    </m:Error>
  </detail>
</soap:Fault>

4. 标准错误码

# SOAP 1.2 Code
soap:VersionMismatch   版本不匹配
soap:MustUnderstand    必须理解的 header 未处理
soap:DataEncodingUnknown 数据编码未知
soap:Sender            发送方错误(参数错误)
soap:Receiver          接收方错误(服务异常)

# SOAP 1.1 faultcode
soap:VersionMismatch
soap:MustUnderstand
soap:Client
soap:Server

5. 处理 Fault

# 客户端解析错误
# Python(zeep)示例
from zeep import Client, Fault

client = Client("http://example.com/service?wsdl")
try:
    result = client.service.GetPrice(Item="Invalid")
except Fault as e:
    print("SOAP 错误:", e.message)
    print("错误码:", e.code)
    print("详情:", e.details)

SOAP HTTP Binding

SOAP HTTP Binding

1. HTTP 传输

# SOAP 最常用的传输方式
# 通过 HTTP POST 发送 XML 消息

# HTTP 请求头
POST /ws/service HTTP/1.1
Host: example.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 452

2. SOAP 1.2 请求示例

POST /ws/price HTTP/1.1
Host: example.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 300

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  xmlns:m="http://example.com/ws">
  <soap:Body>
    <m:GetPrice>
      <m:Item>Apples</m:Item>
    </m:GetPrice>
  </soap:Body>
</soap:Envelope>

3. SOAP 1.1 请求示例

POST /ws/price HTTP/1.1
Host: example.com
Content-Type: text/xml; charset=utf-8
Content-Length: 300
SOAPAction: "http://example.com/ws/GetPrice"

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:m="http://example.com/ws">
  <soap:Body>
    <m:GetPrice>
      <m:Item>Apples</m:Item>
    </m:GetPrice>
  </soap:Body>
</soap:Envelope>

4. 响应示例

HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 250

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  xmlns:m="http://example.com/ws">
  <soap:Body>
    <m:GetPriceResponse>
      <m:Price>1.50</m:Price>
    </m:GetPriceResponse>
  </soap:Body>
</soap:Envelope>

5. HTTP 状态码

# 成功
200 OK               正常响应

# 错误
400 Bad Request      请求格式错误
404 Not Found        服务不存在
500 Internal Server Error  服务端错误
# 500 响应体通常包含 Fault

# 内容类型
SOAP 1.2: application/soap+xml
SOAP 1.1: text/xml + SOAPAction 头

SOAP 实例

SOAP 实例

1. 完整场景:天气预报服务

# 请求:查询城市天气
POST /weather HTTP/1.1
Host: api.example.com
Content-Type: application/soap+xml; charset=utf-8

<?xml version="1.0"?>
<soap:Envelope
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  xmlns:w="http://example.com/weather">
  <soap:Header>
    <w:APIKey>KEY-12345</w:APIKey>
  </soap:Header>
  <soap:Body>
    <w:GetWeather>
      <w:City>北京</w:City>
      <w:Days>3</w:Days>
    </w:GetWeather>
  </soap:Body>
</soap:Envelope>

# 响应
<soap:Envelope ...>
  <soap:Body>
    <w:GetWeatherResponse>
      <w:Forecast>
        <w:Date>2026-08-18</w:Date>
        <w:Temperature>32°C</w:Temperature>
        <w:Condition>晴</w:Condition>
      </w:Forecast>
      <w:Forecast>
        <w:Date>2026-08-19</w:Date>
        <w:Temperature>33°C</w:Temperature>
        <w:Condition>多云</w:Condition>
      </w:Forecast>
    </w:GetWeatherResponse>
  </soap:Body>
</soap:Envelope>

2. Python 调用 SOAP 服务

# 安装 zeep
# pip install zeep

from zeep import Client

# 根据 WSDL 创建客户端
client = Client("http://api.example.com/weather?wsdl")

# 调用服务(方法名来自 WSDL)
result = client.service.GetWeather(
    City="北京",
    Days=3
)

for forecast in result.Forecast:
    print(f"{forecast.Date}: "
          f"{forecast.Temperature}, {forecast.Condition}")

3. Java 调用 SOAP 服务

// 使用 JAX-WS 生成的客户端
WeatherService service = new WeatherService();
WeatherPort port = service.getWeatherPort();

// 设置认证 header
BindingProvider bp = (BindingProvider) port;
Map<String, Object> headers = new HashMap<>();
headers.put("APIKey", "KEY-12345");
bp.getRequestContext().putAll(headers);

// 调用
ForecastList result = port.getWeather("北京", 3);
for (Forecast f : result.getForecast()) {
    System.out.println(f.getDate() + ": "
        + f.getTemperature());
}

SOAP 总结

SOAP 总结

1. 核心要点

  • 消息结构:Envelope > Header + Body
  • 命名空间:SOAP 1.1/1.2 命名空间不同
  • 错误处理:Fault 元素报告错误
  • 传输:通常基于 HTTP POST
  • 契约:WSDL 描述接口

2. SOAP 的优点

  • 标准化程度高,跨语言跨平台
  • 强类型契约,接口清晰
  • 安全标准成熟(WS-Security)
  • 支持事务与可靠消息

3. SOAP 的缺点

  • XML 消息冗长,带宽占用高
  • 解析性能低
  • 学习曲线陡峭
  • 调试困难(消息复杂)

4. 何时选择 SOAP

  • 企业级应用集成
  • 金融/电信等对安全要求高的场景
  • 已有 SOAP 基础设施的存量系统
  • 需要事务、可靠消息等 WS-* 能力

5. 现代替代

REST + JSON         互联网 API 主流
gRPC                高性能 RPC
GraphQL             灵活查询
Message Queue       Kafka/RabbitMQ(异步)

# 建议
# 新项目优先 REST/gRPC
# 对接老系统时掌握 SOAP 基础即可

SOAP 学习指南

SOAP 学习指南

1. 学习路径

1. 理解 XML 基础与命名空间
2. 掌握 SOAP 消息结构(Envelope/Header/Body/Fault)
3. 熟悉 HTTP Binding(请求/响应格式)
4. 理解 WSDL 接口描述
5. 用客户端库实践(zeep/JAX-WS/SoapUI)
6. 了解 WS-Security 等扩展

2. 实践建议

  • 用 SoapUI 调试 SOAP 服务(免费工具)
  • 从公共 SOAP 服务练手(如天气、汇率)
  • 对比 SOAP 与 REST 的请求差异
  • 阅读 WSDL 理解服务契约

3. 调试工具

SoapUI          SOAP 调试与测试(推荐)
Postman         支持 SOAP 请求
Charles/Fiddler HTTP 抓包
Wireshark       底层报文分析

4. 常见问题

# Q: 命名空间错误?
# A: 检查 Envelope 命名空间版本

# Q: Content-Type 错误?
# A: 1.2 用 application/soap+xml,
#    1.1 用 text/xml + SOAPAction

# Q: 无法解析 WSDL?
# A: 确认 WSDL URL 可访问,XSD 引用正确

# Q: 认证失败?
# A: 检查 Header 中 Security/Token 配置

5. 资源推荐

W3C 规范:  www.w3.org/TR/soap12
WSDL 规范: www.w3.org/TR/wsdl
zeep 文档: docs.python-zeep.org
SoapUI:    www.soapui.org

# 结语
# SOAP 虽老但仍在企业界广泛应用,
# 理解其原理对系统集成和运维很重要。
第 1 / 11 节