Web服务:REST与SOAP协议详解
1. 引言
在网络应用开发中,我们常常需要调用服务器端脚本执行任务,并且要设计数据结构来传输信息,编写处理数据传输的程序。然而,当我们希望让服务器端程序更广泛地被使用时,标准化接口就显得尤为重要,这便是Web服务的基础。
Web服务提供了应用程序编程接口(API),允许客户端应用程序构建与服务的接口。虽然任何互联网协议都可用于创建Web服务,但XML和HTTP是比较常用的选择。接下来,我们将详细介绍REST和SOAP这两种协议,以及它们在Ajax应用中的应用。
2. REST:表述性状态转移
2.1 REST的核心原则
REST基于两个主要原则进行通用网络设计:
-
资源由URL表示
:资源可看作是“名词”,指代我们在Web服务API中要处理的实体,如文档、人员、会议、位置等。在REST应用中,每个资源都有唯一的URL。
-
操作通过标准HTTP方法执行
:使用GET、POST、PUT和DELETE等HTTP方法对资源进行操作,这些操作可视为作用于资源的“动词”。
2.2 假设的REST示例
为了更好地理解REST的应用,我们来看一个假设的例子。假设有一个允许作者提交、编辑和阅读文章的Web服务,应用RESTful原则设计该应用时,会有以下情况:
-
唯一URL
:每个提交的文章都有唯一的URL,例如
http://somedomain.com/articles/173
,或者
http://somedomain.com/articles/list.php?id=173
也满足要求。需要注意的是,REST要求URL唯一,但并不意味着每个资源都必须有对应的物理页面,很多情况下资源是在请求时由Web服务生成的,比如通过数据库查询。
-
获取文章
:客户端应用使用HTTP GET请求到文章的URL,即可获取文章进行阅读或编辑。
-
上传新文章
:使用POST请求,包含文章的相关信息,服务器会响应新上传文章的URL。
-
上传编辑后的文章
:使用PUT请求,包含修改后的内容。
-
删除文章
:使用HTTP DELETE请求删除特定文章。
通过这种方式,Web服务使用了熟悉的万维网接口,无需设计专门的API方法库,标准HTTP方法就足够了。实际上,万维网本身就是一个REST应用。
2.3 使用GET查询信息
在RESTful应用中,使用HTTP GET请求时,重要的一点是它永远不会改变服务器状态。也就是说,GET请求仅用于从服务器获取信息,而不用于添加或修改已有信息。而POST、PUT和DELETE请求则可能会改变服务器状态。
2.4 无状态操作
RESTful应用中的所有服务器交互都应该是无状态的。这意味着每个请求本身必须包含服务器执行所需任务的所有信息,而不依赖于服务器当前的状态或上下文。例如,不能要求服务器参考之前请求中发送的信息。
2.5 REST的实际应用
2.5.1 读取可用文章列表
可用文章列表是一个资源,由于Web服务遵循REST原则,我们期望它提供一个URL来访问该资源,例如
http://somedomain.com/articles/list.php
。因为我们只是查询信息,所以使用HTTP GET请求到该URL,服务器可能会返回如下XML:
<articles>
<article>
<id>173</id>
<title>New Concepts in Ajax</title>
<author>P.D. Johnstone</author>
</article>
<article>
<id>218</id>
<title>More Ajax Ideas</title>
<author>S.N. Braithwaite</author>
</article>
<article>
<id>365</id>
<title>Pushing the Ajax Envelope</title>
<author>Z.R. Lawson</author>
</article>
</articles>
2.5.2 获取特定文章
同样,获取特定文章也是一个信息查询请求,使用HTTP GET请求。例如,请求
http://somedomain.com/articles/list.php?id=218
,可能会收到如下响应:
<article>
<id>218</id>
<title>More Ajax Ideas</title>
<author>S.N. Braithwaite</author>
</article>
2.5.3 上传新文章
上传新文章需要使用POST请求。在类似前面假设的情况下,服务器可能会为新文章分配id值,我们只需对标题和作者元素进行参数和值对的编码:
var articleTitle = 'Another Angle on Ajax';
var articleAuthor = 'K.B. Schmidt';
var url = '/articles/upload.php';
var poststring = "title="+encodeURI(articleTitle)
+"&author="+encodeURI(articleAuthor);
http.onreadystatechange = callbackFunction();
http.open('POST', url, true);
http.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", poststring.length);
http.send(poststring);
2.6 现实世界中的REST:亚马逊REST API
领先的在线书店亚马逊提供了一组REST Web服务,帮助开发者将亚马逊的浏览和购物功能集成到他们的Web应用中。亚马逊常将REST协议称为XML-over-HTTP或XML/HTTP。
通过创建包含所需搜索参数(如出版商、排序顺序、作者等)的参数/值对的URL,然后向该URL发送GET请求,亚马逊Web服务会返回包含产品详细信息的XML文档。我们可以解析该XML,创建DOM对象以在网页中显示,或为应用程序的进一步处理提供数据。
需要注意的是,开发亚马逊Web服务的客户端应用程序需要获取开发者令牌,在构造REST请求时需要使用该令牌。此外,还可以获取亚马逊联盟ID,通过在网站上提供亚马逊服务来赚钱。具体信息可查看
http://www.amazon.com
。
下面是一个开发REST请求以返回书籍列表的示例。我们请求出版的书籍列表:
$url = 'http://xml.amazon.com/onca/xml3';
$assoc_id = "XXXXXXXXXX"; // 你的亚马逊联盟ID
$dev_token = "ZZZZZZZZZZ"; // 你的开发者令牌
$manuf = "Sams";
$url = "http://xml.amazon.com/onca/xml3";
$url .= "?t=".$assoc_id;
$url .= "&dev-t=".$dev_token;
$url .= "&ManufacturerSearch=".$ manuf;
$url .= "&mode=books";
$url .= "&sort=+salesrank";
$url .= "&offer=All";
$url .="&type=lite";
$url .= "&page=1";
$url .= "&f=xml";
提交该URL后,我们会收到一个包含所有匹配书籍详细信息的XML文件。以下是该XML文件的部分内容:
<?xml version="1.0" encoding="UTF-8" ?>
<ProductInfo xmlns:xsi="http://www.w3.org/
2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation
="http://xml.amazon.com/schemas3/dev-lite.xsd">
<Request>
<Args>
<Arg value="Mozilla/4.0 (compatible; MSIE 6.0;
Windows NT 5.1; SV1; .NET CLR 1.1.4322)"
name="UserAgent" />
<Arg value="0G2CGCT7MRWB37PXAS4B" name="RequestID" />
<Arg value="All" name="offer" />
<Arg value="us" name="locale" />
<Arg value="1" name="page" />
<Arg value="ZZZZZZZZZZZ" name="dev-t" />
<Arg value="XXXXXXXXXXX" name="t" />
<Arg value="xml" name="f" />
<Arg value="books" name="mode" />
<Arg value="Sams" name="ManufacturerSearch" />
<Arg value="lite" name="type" />
<Arg value="salesrank" name="sort" />
</Args>
</Request>
<TotalResults>5051</TotalResults>
<TotalPages>506</TotalPages>
<Details url="http://www.amazon.com/exec/obidos/ASIN/
0672327236/themousewhisp-20?dev-t=
1WPTTG90FS816BXMNFG2%26camp=2025%26link_code=xm2">
<Asin>0672327236</Asin>
<ProductName>Sams Teach Yourself Microsoft SharePoint
2003 in 10 Minutes (Sams Teach Yourself
in 10 Minutes)</ProductName>
<Catalog>Book</Catalog>
<Authors>
<Author>Colin Spence</Author>
<Author>Michael Noel</Author>
</Authors>
<ReleaseDate>06 December, 2004</ReleaseDate>
<Manufacturer>Sams</Manufacturer>
<ImageUrlSmall>http://images.amazon.com/images/P/
0672327236.01.THUMBZZZ.jpg</ImageUrlSmall>
<ImageUrlMedium>http://images.amazon.com/images/P/
0672327236.01.MZZZZZZZ.jpg</ImageUrlMedium>
<ImageUrlLarge>http://images.amazon.com/images/P/
0672327236.01.LZZZZZZZ.jpg</ImageUrlLarge>
<Availability>Usually ships in 24 hours</Availability>
<ListPrice>$14.99</ListPrice>
<OurPrice>$10.19</OurPrice>
<UsedPrice>$9.35</UsedPrice>
</Details>
2.7 REST与Ajax
由于XMLHTTPRequest对象具有直接处理HTTP请求类型和URL的方法,因此访问RESTful Web服务变得非常简单。因为我们知道Web服务API暴露的每个资源都有唯一的URL,且服务提供的方法是标准HTTP方法,所以构造所需的XMLHTTPRequest调用就变得轻而易举。能够从Ajax应用中访问各种Web服务,并在应用中使用返回的信息,这是非常有吸引力的,尤其是当我们可以使用一致且简单的接口协议时。
下面是一个简单的mermaid流程图,展示了REST请求的基本流程:
graph LR
A[客户端] --> B[创建包含参数的URL]
B --> C[发送HTTP请求(GET/POST等)]
C --> D[服务器处理请求]
D --> E[返回XML文档]
E --> F[客户端解析XML]
3. 使用SOAP的Web服务
3.1 从REST到SOAP
前面我们介绍了REST协议,它适用于资源导向的服务,提供了定位资源和操作资源的基本方法。然而,在某些情况下,我们更关注Web服务能够执行的操作,而不是它能控制的资源,这类服务可称为动作导向的服务。SOAP(简单对象访问协议)是设计动作导向Web服务最流行和广泛使用的协议。
3.2 SOAP协议的背景
SOAP起源于20世纪90年代末,当时XML还是一种新兴的Web技术。2000年,SOAP被提交给W3C。SOAP和另一个基于XML的Web服务协议XML - RPC有共同的发展历程。
SOAP本质上是一种将远程过程调用(请求在远程机器上调用程序)封装到XML包装器中的标准化方法。许多企业参与了SOAP的早期开发,包括IBM、微软和Userland。后来,SOAP的开发转交给了W3C的XML协议工作组。你可以从
http://www.w3.org/2000/xp/Group/
获取SOAP规范的最新信息。
3.3 SOAP协议
3.3.1 SOAP请求的组成
SOAP是一种基于XML的消息协议。SOAP请求是一个XML文档,主要由以下部分组成:
-
信封
:定义文档为SOAP请求。
-
主体元素
:包含关于调用和预期响应的信息。
-
可选的头部和错误元素
:携带补充信息。
下面是一个SOAP请求的骨架:
<?xml version="1.0"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
... 各种命令 ...
</SOAP-ENV:Header>
<SOAP-ENV:Body>
... 各种命令 ...
<SOAP-ENV:Fault>
... 各种命令 ...
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
3.3.2 详细解析
-
信封元素
:SOAP请求的根元素是Envelope,第一行声明了
xmlns:soap命名空间,其值必须为xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"。命名空间用于唯一分组一组XML元素或属性,避免与其他模式中的名称冲突。encodingStyle属性定义了消息中使用的数据类型。 - 头部元素 :可选元素,如果存在,必须是消息中的第一个元素。头部元素中定义的属性决定了接收应用程序如何处理消息。
- 主体元素 :包含要发送给最终接收者的消息。序列化的方法参数包含在SOAP请求的主体元素中,调用的XML元素必须紧跟SOAP主体的开始XML标签,并且名称必须与要调用的远程方法相同。
- 错误元素 :主体元素中可能包含一个(且仅一个)Fault元素,用于携带可能发生的错误信息。Fault元素有多个子元素,如faultcode、faultstring和detail,包含错误条件的具体细节。
3.3.3 SOAP请求的代码示例
下面是一个典型的SOAP请求示例:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=
"http://schemas.xmlsoap.org/soap/envelope/" SOAP
ENV:encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/">
<SOAP-ENV:Body>
<m:GetInvoiceTotal xmlns:m=
"http://www.somedomain.com/invoices">
<m:Invoice>77293</m:Invoice>
</m:GetInvoiceTotal>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
在上述示例中,
m:GetInvoiceTotal
和
m:Invoice
元素是特定应用的元素,不是SOAP本身的一部分,它们构成了SOAP信封中的消息。
3.3.4 SOAP响应示例
对应的SOAP响应可能如下:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=
"http://schemas.xmlsoap.org/soap/envelope/" SOAP
ENV:encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/">
<SOAP-ENV:Body>
<m:ShowInvoiceTotal xmlns:m=
"http://www.somedomain.com/invoices">
<m:InvoiceTotal>3295.00</m:InvoiceTotal>
</m:ShowInvoiceTotal>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
3.4 通过HTTP发送SOAP请求
SOAP消息可以通过HTTP GET或HTTP POST传输。如果通过HTTP POST发送,SOAP消息至少需要设置一个HTTP头部,用于定义
Content-Type
:
Content-Type: text/xml
成功的SOAP交换后,预期会收到带有适当HTTP头部的SOAP响应:
HTTP/1.1 200 OK
Content-Type: text/xml
Content-Length: yyy
<?xml version="1.0"?>
下面是一个表格,对比REST和SOAP的特点:
| 协议 | 适用场景 | 接口特点 | 数据格式 |
| ---- | ---- | ---- | ---- |
| REST | 资源导向服务 | 基于URL和HTTP方法,简单直观 | 通常为XML或JSON |
| SOAP | 动作导向服务 | 基于XML消息,结构复杂 | XML |
再来看一个mermaid流程图,展示SOAP请求的流程:
graph LR
A[客户端] --> B[创建SOAP请求XML]
B --> C[设置HTTP头部(POST时)]
C --> D[发送HTTP请求(GET/POST)]
D --> E[服务器处理SOAP请求]
E --> F[返回SOAP响应XML]
F --> G[客户端解析SOAP响应]
综上所述,REST和SOAP是两种不同但都非常重要的Web服务协议。REST简单直观,适用于资源导向的服务;SOAP结构复杂,但在动作导向的服务中表现出色。开发者可以根据具体的应用场景选择合适的协议。
4. 对比SOAP和REST
4.1 功能特性对比
| 特性 | REST | SOAP |
|---|---|---|
| 设计理念 | 资源导向,围绕资源的增删改查操作 | 动作导向,关注服务执行的具体动作 |
| 接口复杂度 | 基于标准HTTP方法,接口简单直观 | 基于XML消息,结构复杂,需要遵循严格规范 |
| 数据格式 | 通常使用XML或JSON,格式灵活 | 仅使用XML,格式固定 |
| 状态管理 | 无状态,每个请求独立,不依赖服务器状态 | 可支持有状态和无状态,相对灵活但实现复杂 |
| 错误处理 | 利用HTTP状态码表示错误,简单但信息有限 | 有专门的Fault元素详细描述错误信息 |
| 安全性 | 依赖HTTP协议的安全机制,如HTTPS | 支持多种安全机制,如WS - Security,安全性高 |
| 性能 | 轻量级,请求响应速度快,适合对性能要求高的场景 | 消息体积大,处理复杂,性能相对较低 |
| 跨平台兼容性 | 基于标准HTTP协议,跨平台兼容性好 | 不同平台对SOAP的实现可能存在差异,兼容性稍弱 |
4.2 应用场景对比
-
REST适用场景
- 资源管理类应用 :如博客系统、电商系统中的商品管理等,需要对文章、商品等资源进行增删改查操作。
- 移动应用开发 :移动设备对性能和网络要求较高,REST的轻量级特性可以满足这些需求。
- 开放API :为第三方开发者提供接口,简单的接口和灵活的数据格式便于开发者集成。
-
SOAP适用场景
- 企业级应用集成 :企业内部不同系统之间的集成,需要保证数据的安全性和完整性,SOAP的严格规范和安全机制可以满足要求。
- 金融交易系统 :对交易的准确性和安全性要求极高,SOAP的错误处理和安全机制可以有效保障交易的顺利进行。
- 复杂业务逻辑处理 :当服务需要执行复杂的业务逻辑,并且需要详细的错误信息和事务处理时,SOAP更为合适。
4.3 代码实现对比
以下是一个简单的对比示例,分别使用REST和SOAP实现获取用户信息的功能。
REST实现
// 创建XMLHttpRequest对象
var http = new XMLHttpRequest();
// 定义请求的URL
var url = 'http://example.com/api/users/1';
// 打开请求
http.open('GET', url, true);
// 发送请求
http.send();
// 监听状态变化
http.onreadystatechange = function() {
if (http.readyState === 4 && http.status === 200) {
// 解析返回的JSON数据
var user = JSON.parse(http.responseText);
console.log(user);
}
};
SOAP实现
// 创建XMLHttpRequest对象
var http = new XMLHttpRequest();
// 定义请求的URL
var url = 'http://example.com/soap/service';
// 定义SOAP请求XML
var soapRequest = `<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetUserInfo xmlns:m="http://example.com/soap">
<m:UserId>1</m:UserId>
</m:GetUserInfo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>`;
// 打开请求
http.open('POST', url, true);
// 设置请求头部
http.setRequestHeader('Content-Type', 'text/xml');
// 发送请求
http.send(soapRequest);
// 监听状态变化
http.onreadystatechange = function() {
if (http.readyState === 4 && http.status === 200) {
// 解析返回的XML数据
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(http.responseText, 'text/xml');
var userInfo = xmlDoc.getElementsByTagName('m:UserInfo')[0];
console.log(userInfo);
}
};
从代码实现可以看出,REST的代码相对简洁,而SOAP的代码需要构建复杂的XML请求和响应。
下面是一个mermaid流程图,对比REST和SOAP的请求流程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([客户端]):::startend --> B(创建请求):::process
B --> C{选择协议}:::decision
C -->|REST| D(创建包含参数的URL):::process
C -->|SOAP| E(创建SOAP请求XML):::process
D --> F(发送HTTP请求):::process
E --> G(设置HTTP头部):::process
G --> H(发送HTTP请求):::process
F --> I(服务器处理请求):::process
H --> I
I --> J(返回响应):::process
J --> K(客户端解析响应):::process
K --> L([结束]):::startend
5. 实际应用案例分析
5.1 REST应用案例:GitHub API
GitHub是一个知名的代码托管平台,它提供了RESTful API,允许开发者与GitHub的各种资源进行交互,如仓库、用户、问题等。
操作步骤
-
获取用户信息
-
构造URL:
https://api.github.com/users/{username},其中{username}是要查询的GitHub用户名。 -
发送HTTP GET请求:可以使用工具如
curl或编程语言中的HTTP库发送请求。 - 解析响应:返回的是JSON格式的数据,包含用户的详细信息,如用户名、头像链接、仓库数量等。
-
构造URL:
# 使用curl获取用户信息
curl https://api.github.com/users/octocat
-
创建仓库
-
构造URL:
https://api.github.com/user/repos。 - 发送HTTP POST请求:请求体中包含仓库的相关信息,如仓库名称、描述等,以JSON格式发送。
-
设置请求头部:
Content-Type: application/json,并使用GitHub的访问令牌进行身份验证。
-
构造URL:
// 使用JavaScript创建仓库
var http = new XMLHttpRequest();
var url = 'https://api.github.com/user/repos';
var data = JSON.stringify({
"name": "new - repository",
"description": "This is a new repository"
});
http.open('POST', url, true);
http.setRequestHeader('Content-Type', 'application/json');
http.setRequestHeader('Authorization', 'token YOUR_ACCESS_TOKEN');
http.send(data);
5.2 SOAP应用案例:企业财务系统集成
某大型企业有多个业务系统,如销售系统、采购系统和财务系统,需要将这些系统集成起来,实现数据的共享和业务流程的自动化。采用SOAP协议进行系统间的通信。
操作步骤
- 定义服务接口 :在财务系统中定义一系列的SOAP服务接口,如查询账户余额、创建发票等。
- 生成WSDL文件 :WSDL(Web Services Description Language)是用于描述SOAP服务的XML文件,它定义了服务的接口、输入输出参数等信息。
- 客户端开发 :在销售系统和采购系统中开发客户端程序,根据WSDL文件生成SOAP请求,调用财务系统的服务。
- 服务调用 :客户端发送SOAP请求到财务系统的服务端点,财务系统处理请求并返回SOAP响应。
<!-- 示例SOAP请求:查询账户余额 -->
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetAccountBalance xmlns:m="http://example.com/finance">
<m:AccountId>12345</m:AccountId>
</m:GetAccountBalance>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
6. 总结与展望
6.1 总结
REST和SOAP是两种重要的Web服务协议,它们各有优缺点和适用场景。REST以其简单、轻量级和灵活的特点,在资源管理和移动应用开发等领域得到广泛应用;SOAP则凭借其严格的规范、强大的功能和高安全性,在企业级应用集成和金融交易等场景中发挥重要作用。开发者在选择协议时,需要根据具体的业务需求、性能要求、安全性要求等因素进行综合考虑。
6.2 展望
- 技术融合趋势 :未来,REST和SOAP可能会相互融合,取长补短。例如,在RESTful API中引入SOAP的安全机制,提高API的安全性;或者在SOAP服务中借鉴REST的轻量级设计理念,提升服务的性能。
- 新兴技术的影响 :随着微服务架构、容器化技术和人工智能的发展,Web服务协议也将面临新的挑战和机遇。微服务架构强调服务的独立性和可扩展性,REST的简单性更适合微服务的开发;而人工智能的应用可能会对数据的安全性和准确性提出更高要求,SOAP的严格规范和强大功能将有更大的发挥空间。
- 标准化和规范化 :Web服务协议的标准化和规范化将进一步加强,不同平台和系统之间的兼容性将得到提高,降低开发者的开发成本和维护难度。
总之,REST和SOAP在Web服务领域都有着不可替代的地位,它们将随着技术的发展不断演进,为开发者提供更强大、更灵活的服务。开发者需要不断学习和掌握这两种协议,以适应不断变化的技术环境。
超级会员免费看
584

被折叠的 条评论
为什么被折叠?



