SOAP全称为简单对象访问协议,是一种基于XML的协议,用于在计算机网络中交换结构化信息,它独立于传输协议,可搭配HTTP、SMTP等多种协议使用,是早期Web服务体系中实现跨平台、跨语言通信的重要标准。SOAP协议的设计目标是简单易用,通过标准化的XML格式封装请求和响应数据,让不同系统之间可以顺畅完成信息交互。

SOAP协议的核心特点
SOAP协议具备多个明显的核心特点,这些特点让它能够在分布式系统中广泛应用:
- 基于XML格式:所有SOAP消息都使用XML编写,XML的自描述性让不同平台都可以解析内容,解决了跨语言、跨系统的数据兼容问题。
- 独立于传输层:SOAP协议本身不依赖特定传输协议,虽然最常搭配HTTP使用,但也可以适配其他支持文本传输的协议。
- 可扩展性强:SOAP消息支持自定义头部元素,开发者可以根据业务需求添加额外的控制信息,比如认证信息、事务标识等。
- 标准化程度高:SOAP有完整的W3C标准规范,不同厂商实现的SOAP服务可以互相通信,降低了系统集成的成本。
SOAP消息的XML结构组成
一个完整的SOAP消息是一个XML文档,必须包含<Envelope>根元素,同时可以包含<Header>和<Body>两个子元素,其中<Body>是必需元素,<Header>是可选元素。下面我们逐个拆解每个部分的作用和结构规则。
1. Envelope元素
<Envelope>是SOAP消息的根元素,所有其他SOAP元素都必须包含在这个元素内部。它必须声明SOAP的命名空间,用来标识当前消息遵循的SOAP版本规范。目前常用的SOAP版本有1.1和1.2,两者的命名空间不同:
- SOAP 1.1的命名空间为:http://schemas.xmlsoap.org/soap/envelope/
- SOAP 1.2的命名空间为:http://www.w3.org/2003/05/soap-envelope
如果消息中使用了SOAP 1.2的命名空间,却按照1.1的规则编写内容,解析时会直接报错。下面是一个基础的SOAP 1.1信封示例:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- 其他SOAP元素放在这里 -->
</soap:Envelope>
2. Header元素
<Header>是SOAP消息的可选元素,如果存在则必须作为<Envelope>的第一个子元素。它用来存放一些附加的控制信息,比如消息认证信息、消息优先级、路由信息等,这些信息通常和具体的业务数据无关,属于消息处理的辅助信息。
Header中的每个子元素都可以包含两个可选的SOAP属性:
- mustUnderstand:取值为0或1,1表示该头部条目必须由接收方处理,如果接收方无法处理则返回错误;0表示该条目是可选的,接收方可以忽略。
- actor:用来指定该头部条目的处理者,因为SOAP消息可能在多个中间节点转发,这个属性可以标识哪个节点需要处理该条目。
下面是一个包含认证信息的Header示例:
<soap:Header>
<auth:Authentication soap:mustUnderstand="1"
xmlns:auth="http://ipipp.com/auth">
<auth:Username>test_user</auth:Username>
<auth:Password>test_pass123</auth:Password>
</auth:Authentication>
</soap:Header>
3. Body元素
<Body>是SOAP消息的必需元素,用来存放实际的业务请求或响应数据,是消息的核心内容部分。如果是请求消息,Body中通常包含调用的方法名和对应的参数;如果是响应消息,Body中通常包含方法的返回结果或者错误信息。
下面是一个调用获取用户信息的SOAP请求Body示例:
<soap:Body>
<getUser xmlns="http://ipipp.com/user_service">
<userId>10001</userId>
<includeDetail>true</includeDetail>
</getUser>
</soap:Body>
对应的响应Body示例:
<soap:Body>
<getUserResponse xmlns="http://ipipp.com/user_service">
<userInfo>
<id>10001</id>
<name>张三</name>
<age>28</age>
<email>zhangsan@ipipp.com</email>
</userInfo>
</getUserResponse>
</soap:Body>
4. Fault元素
<Fault>元素用来在SOAP消息中携带错误信息,它必须作为<Body>的子元素出现,当消息处理过程中出现错误时,响应消息的Body中会包含Fault元素,用来告知调用方错误原因。
SOAP 1.1的Fault元素包含以下子元素:
- faultcode:错误代码,用来标识错误的类型,比如VersionMismatch表示SOAP版本不匹配,MustUnderstand表示必须处理的Header条目无法处理。
- faultstring:可读的错误描述信息,用来说明错误的具体内容。
- faultactor:可选,标识导致错误的SOAP节点地址。
- detail:可选,用来存放与Body处理相关的详细错误信息,如果是Header相关的错误不会放在这个元素中。
下面是一个错误响应的示例:
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>请求参数格式错误,userId必须为数字</faultstring>
<detail>
<error>
<param>userId</param>
<message>参数类型不匹配,期望数字类型</message>
</error>
</detail>
</soap:Fault>
</soap:Body>
完整的SOAP消息示例
下面是一个包含Header和Body的完整SOAP 1.1请求消息示例,该消息调用用户服务的getUser方法,同时携带了认证信息:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<auth:Authentication soap:mustUnderstand="1"
xmlns:auth="http://ipipp.com/auth">
<auth:Username>test_user</auth:Username>
<auth:Password>test_pass123</auth:Password>
</auth:Authentication>
</soap:Header>
<soap:Body>
<getUser xmlns="http://ipipp.com/user_service">
<userId>10001</userId>
<includeDetail>true</includeDetail>
</getUser>
</soap:Body>
</soap:Envelope>
SOAP协议的适用场景
虽然现在RESTful风格的Web服务使用更广泛,但SOAP协议在一些场景下仍然有不可替代的优势:
- 需要严格的接口规范和安全要求的场景,比如金融、电信等行业的内部系统集成,SOAP的标准化和可扩展的Header可以很好地支持复杂的安全校验。
- 需要跨语言、跨平台且对兼容性要求极高的场景,SOAP基于XML的特性让几乎所有支持XML解析的系统都可以对接。
- 已经基于SOAP构建了大量存量服务的系统,迁移成本高,仍然会继续使用SOAP协议。
如果业务场景对性能要求高、接口设计需要更灵活轻量,通常更推荐选择RESTful风格的接口,SOAP的XML封装会带来更多的传输和解析开销。