目录
-
第一部分:SOAP 基础理论
(图片来源网络,侵删)- 什么是 WebService?
- 什么是 SOAP?
- SOAP 的核心组成部分
- SOAP vs. REST (为什么选择 SOAP?)
- SOAP 应用场景
-
第二部分:Java (JAX-WS) 开发实战
- 环境准备
- 开发一个 SOAP WebService (服务端)
- 调用 SOAP WebService (客户端)
- 高级主题:使用 Maven 和 Tomcat 部署
-
第三部分:Python 开发实战
- 环境准备
- 使用
zeep库调用现有的 SOAP WebService (客户端)
-
第四部分:常用工具与进阶
- SOAP UI 测试工具
- WSDL 解析
- 最佳实践与常见问题
第一部分:SOAP 基础理论
什么是 WebService?
WebService 是一种跨编程语言和跨操作系统平台的远程调用技术,它允许你通过标准的 Web 协议(如 HTTP)来暴露应用程序的功能,使得其他程序可以像调用本地方法一样调用这些功能。

什么是 SOAP?
SOAP (Simple Object Access Protocol,简单对象访问协议) 是一种基于 XML 的协议,用于在网络上交换结构化的信息,它不是一种“RESTful”风格的 API,而是一套严格的规范。
你可以把 SOAP 想象成一种非常正式、有固定格式的“信件”,而 REST 则像一张灵活的“便条”。
SOAP 的核心组成部分
一个完整的 SOAP 通信过程主要包含三个部分:
-
SOAP Envelope (信封)
(图片来源网络,侵删)- 这是 SOAP 消息的根元素,定义了消息的内容和如何处理它。
- 必须包含
<soap:Envelope>。
-
SOAP Header (头部)
- 可选部分,用于包含与消息相关的元数据,如身份验证信息、事务ID等。
- 就像信封上的“机密”或“加急”标签。
-
SOAP Body (正文)
- 必须包含的部分,它承载了实际的应用程序数据,即要调用的方法名和参数。
- 就像信件的内容本身。
一个简单的 SOAP 请求示例:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<!-- 头部信息,如认证令牌 -->
</soap:Header>
<soap:Body>
<m:GetStockPrice xmlns:m="http://www.example.com/stock">
<m:StockName>IBM</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
一个简单的 SOAP 响应示例:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/soap-envelope">
<soap:Body>
<m:GetStockPriceResponse xmlns:m="http://www.example.com/stock">
<m:Price>180.50</m:Price>
</m:GetStockPriceResponse>
</soap:Body>
</soap:Envelope>
SOAP vs. REST
| 特性 | SOAP | REST |
|---|---|---|
| 协议 | 严格依赖 XML,通常通过 HTTP/SMTP/FTP 等传输。 | 不强制协议,通常基于 HTTP/HTTPS。 |
| 标准 | 标准(W3C),有严格的规范。 | 架构风格,没有官方标准。 |
| 格式 | 强制使用 XML。 | 支持多种格式,如 JSON, XML, HTML。 |
| 状态 | 无状态(通过 Header 或 Body 传递状态)。 | 无状态(更符合 Web 原生特性)。 |
| 性能 | 由于 XML 解析开销,通常性能较低。 | 由于 JSON 解析快,性能通常更高。 |
| 安全性 | 内置安全标准和扩展(WS-Security)。 | 依赖 HTTPS 和 OAuth 等标准。 |
| 工具支持 | 成熟的工具链(如 WSDL, SOAP UI)。 | 灵活,工具相对简单(Postman 等)。 |
| 使用场景 | 企业级应用、金融、电信等对安全性、事务性要求高的场景。 | 公开 API、移动应用、Web 应用等。 |
SOAP 应用场景
- 企业应用集成:连接不同系统(如 SAP, Oracle, Salesforce)。
- 金融交易:银行间转账、支付网关,需要高安全性和事务保证。
- 电信:运营商的计费和信令系统。
- 政府服务:需要遵循严格规范的公共服务接口。
第二部分:Java (JAX-WS) 开发实战
我们将使用 Java 的标准 API JAX-WS (Java API for XML Web Services) 来开发一个 SOAP 服务,JAX-WS 使得开发过程非常简单,很多工作可以由 JDK 自带的工具 wsimport 完成。
环境准备
- JDK 8 或更高版本
- IDE (如 IntelliJ IDEA 或 Eclipse)
- 构建工具 (Maven, 推荐)
开发一个 SOAP WebService (服务端)
我们的目标是创建一个计算器服务,提供 add 和 subtract 方法。
步骤 1:创建 Maven 项目
在 IDE 中创建一个新的 Maven 项目,pom.xml 文件中引入 JAX-WS 依赖,JDK 通常自带了这些 API,但显式声明是好习惯。
<dependencies>
<!-- JAX-WS API (如果JDK没有提供,则需要此依赖) -->
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- JAX-WS RI (参考实现,用于开发) -->
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.3</version>
</dependency>
</dependencies>
步骤 2:创建服务接口和实现类
服务接口 (Calculator.java)
使用 @WebService 注解来标记这是一个 WebService 接口。
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
// @WebService 指定这是一个 WebService
// name: 服务名
// targetNamespace: 命名空间,通常是一个唯一的URI
@WebService(name = "Calculator", targetNamespace = "http://example.com/calculator")
// @SOAPBinding 定义SOAP消息风格
// style = Style.DOCUMENT: 表示使用文档风格的SOAP消息
// use = Use.LITERAL: 表示使用字面量
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL)
public interface Calculator {
// @WebMethod 指定这是一个公开的Web方法
@WebMethod
public int add(int a, int b);
@WebMethod
public int subtract(int a, int b);
}
服务实现类 (CalculatorImpl.java)
实现上面的接口,实现类不需要任何注解。
public class CalculatorImpl implements Calculator {
@Override
public int add(int a, int b) {
System.out.println("Adding " + a + " and " + b);
return a + b;
}
@Override
public int subtract(int a, int b) {
System.out.println("Subtracting " + b + " from " + a);
return a - b;
}
}
步骤 3:发布服务
创建一个主类来发布我们的服务。
import javax.xml.ws.Endpoint;
public class CalculatorPublisher {
public static void main(String[] args) {
// 创建服务的实现实例
CalculatorImpl calculator = new CalculatorImpl();
// 发布服务
// 参数1: 服务的访问地址
// 参数2: 服务的实现对象
Endpoint.publish("http://localhost:8888/calculator", calculator);
System.out.println("Calculator WebService is published at http://localhost:8888/calculator?wsdl");
}
}
运行 CalculatorPublisher,你的 SOAP 服务已经启动了!打开浏览器访问 http://localhost:8888/calculator?wsdl,你应该能看到一个 WSDL (Web Services Description Language) 文件,这个 XML 文件描述了你的服务的所有信息,包括可用的方法、参数和如何调用它。
调用 SOAP WebService (客户端)
客户端开发有两种主要方式:
- 使用
wsimport生成客户端代码 (最常用) - 使用 JAX-WS API 动态调用
这里我们介绍第一种方式,它更简单。
步骤 1:使用 wsimport 生成客户端代码
打开命令行(或使用 Maven 插件),执行以下命令:
wsimport -keep -p com.example.client http://localhost:8888/calculator?wsdl
wsimport: JDK 自带的工具。-keep: 生成的 Java 文件保留。-p com.example.client: 指定生成的代码包名。http://localhost:8888/calculator?wsdl: WSDL 文件的 URL。
执行后,你的项目中会生成一堆 Java 文件(.class 和 .java),这些就是客户端代理代码。
步骤 2:编写客户端调用代码
import com.example.client.Calculator; // 这是 wsimport 生成的服务接口
import com.example.client.Calculator_Service; // 这是 wsimport 生成的服务工厂类
public class CalculatorClient {
public static void main(String[] args) {
// 创建服务工厂实例
Calculator_Service service = new Calculator_Service();
// 从工厂获取服务端点接口
Calculator calculator = service.getCalculatorPort();
// 像调用本地方法一样调用远程方法
int resultAdd = calculator.add(10, 5);
System.out.println("10 + 5 = " + resultAdd);
int resultSubtract = calculator.subtract(10, 5);
System.out.println("10 - 5 = " + resultSubtract);
}
}
运行这个客户端,它会通过 SOAP 协议与服务器通信,并打印出结果。
第三部分:Python 开发实战
Python 开发 SOAP 客户端通常比 Java 更简单,因为不需要生成代码,而是使用一个库来动态解析 WSDL 并调用方法。zeep 是目前最流行的库。
环境准备
- Python 3
- pip (Python 包管理器)
安装 zeep 库:
pip install zeep
使用 zeep 调用现有的 SOAP WebService
我们将调用上面我们用 Java 发布的 http://localhost:8888/calculator?wsdl 服务。
Python 客户端代码 (python_client.py)
from zeep import Client
# WSDL 文件的 URL
wsdl_url = 'http://localhost:8888/calculator?wsdl'
# 创建 zeep 客户端
client = Client(wsdl_url)
# 打印服务信息,了解可用的方法
print("服务端口:", client.service)
print("可用操作:", client.wsdl.dump())
# 调用 add 方法
# zeep 会自动将 Python 参数转换为 SOAP 消息
try:
result_add = client.service.add(a=10, b=5)
print(f"10 + 5 = {result_add}")
# 调用 subtract 方法
result_subtract = client.service.subtract(a=10, b=5)
print(f"10 - 5 = {result_subtract}")
except Exception as e:
print(f"调用服务时出错: {e}")
运行客户端:
python python_client.py
你将看到与 Java 客户端相同的输出。zeep 库非常强大,它会自动处理 WSDL 解析、SOAP 消息的构建和解析,让你专注于业务逻辑。
第四部分:常用工具与进阶
SOAP UI 测试工具
SOAP UI 是一款功能强大的 SOAP 和 REST API 测试工具,对于任何 WebService 它都是必备神器。
- 功能:
- 导入 WSDL 文件,自动生成测试用例。
- 可以修改请求参数,发送请求并查看响应。
- 支持性能测试、负载测试。
- 可以模拟一个 WebService 服务(Mock Service)。
- 使用:
- 下载并安装 SOAP UI。
- 创建一个新的 SOAP Project,输入你的 WSDL 地址。
- 它会自动解析出所有的操作,你可以在右侧的 Request 窗格中编辑并发送请求。
WSDL 解析
WSDL 是服务的“说明书”,理解 WSDL 结构对于调试和手动构建请求非常有帮助。
<types>: 定义了服务使用的数据类型,通常是 XML Schema (XSD)。<message>: 描述了一个操作的数据,一个请求或一个响应。<portType>: 抽象集合,定义了服务的所有可用操作(类似于 Java 接口)。<binding>: 特定端口类型的具体协议和数据格式细节(使用 SOAP/HTTP)。<service>: 相关端点的集合,定义了服务的实际网络地址。
最佳实践与常见问题
-
最佳实践:
- 使用 WSDL First: 先设计 WSDL 契约,再编写实现代码,这有助于前后端分离和接口的稳定性。
- 版本控制: 当服务接口变更时,发布一个新版本(如
v2),而不是直接修改旧版本,避免破坏现有客户端。 - 错误处理: 在 SOAP Body 中定义标准的错误响应结构,方便客户端统一处理。
- 安全性: 对于敏感数据,务必使用 WS-Security 或 HTTPS。
-
常见问题:
javax.xml.ws.soap.SOAPFaultException: 服务端抛出的 SOAP 错误,检查服务端日志和返回的 SOAP Fault 消息。java.net.ConnectException: 客户端无法连接到服务端,检查 URL、端口、防火墙设置。@WebService注解不生效: 确保类和方法是public的。- WSDL 中的命名空间问题: 命名空间是区分不同元素的关键,务必保持一致。
这份教程带你从零开始了解了 SOAP WebService 的核心概念,并分别用 Java 和 Python 完成了服务端开发和客户端调用的完整流程。
- Java (JAX-WS) 的优势在于其官方标准、工具链成熟,适合构建大型、稳定的企业级服务。
- Python (zeep) 的优势在于其简洁的语法和动态调用能力,非常适合快速编写客户端脚本或与现有 SOAP 服务集成。
虽然 REST API 在当今更流行,但 SOAP 在金融、电信等关键领域依然是中流砥柱,掌握 SOAP 技术对于成为一名全栈或企业级开发工程师非常有价值。
