在这个由两部分组成
系列
第一篇文章中,Web 服务专栏作家 Mike Olson 和 Uche Ogbuji 讨论了 Python 可以使用
各种 SOAP 实现,并给出了详细
代码示例。 字串6
在前面
3 部分中,我们已经用 4Suite Server 开发了一个 Web 服务实现,并利用了该产品
SOAP 支持。(请参阅 参考资料。)Python 还有其它
SOAP 实现;实际上,这
象成了很流行
使用 Python
开放源代码活动。在本文中,我们将看一下工作中
Soap.py。关于其它开放源代码
SOAP 项目
更新,请参阅 旁注。但我们马上要讨论
麻烦问题,是 Python SOAP 模块
命名。不同项目之间
交流看上去
象并不多,因为在这些项目
名称间有许多令人困惑
类似
地方。最近,在向同事解释这些供选方案时,我们发现自己记不清楚 SOAPy 和 SOAP.py
特征分别是什么了 ― 而且这还是在我们用过它们很长时间后。这个问题在必须为实际库中
多个模块命名时变得更为严重,请参阅旁注。 字串6
在这个专栏
前三部分中,我们讨论了 4Suite SOAP;在这篇和下篇文章中,我们将提供来自 SOAP.py 和 SOAPy 项目
示例,在这两个项目冻结时,这
象是最深入
讨论了。注意,尽管 W3C
XML 协议工作组已经制订了一个被称为 SOAP 1.2
草案,但各个平台和语言上 SOAP 实现
普遍级别仍是 SOAP 1.1,更早
版本甚至更具代表性。这些日子 SOAP 版本
发展引入了一些复杂性,这些复杂性可能会超过 SOAP 所承诺
简洁性。 字串4
SOAP.py 客户机和服务器 字串1
SOAP.py 包含
是一些基本
东西。没有 Web 服务描述语言(Web Services Description Language,WSDL)或者任何其它附加
东西,只有用 Python 实现
SOAP 客户机和服务器
透明支持。甚至这个包中
一个很
功能也只是与基础架构相关:SOAP.py 支持安全套接字层(SSL)用于加密
SOAP 传输。为使用这个功能,您必须安装 M2Crypto,M2Crypto 是一个库,包含各种加密工具和格式,从 RSA 和 DSA 到 HTTPs、S/MIME 等等。在这一部分,我们不准备讨论 SOAP.py
SSL 支持。 字串3
SOAP 操作摘要
目前为止,SOAP 实用程序
象仍是比较流行
使用 Python
开放源代码活动。下面是该项目
纲要以及它们目前
状态。首先,参与者: 字串1
4Suite SOAP,由 Fourthought 管理
字串6
SOAPy,由 Adam Elman 管理
字串4
SOAP.py,Python 项目
一个 Web 服务项目 字串7
soaplib,由 Secret Labs 管理 字串4
Orchard,由 Ken MacLeod 管理 字串4
字串7
PySOAP,由 Dave Warner 管理
4Suite SOAP 是我们自己
实现,我们在本专栏
前面三部分中使用过(请参阅 参考资料以获得它
链接)。它目前仍在开发中。
SOAPy 是在 2001 年 4 月公布
,目前处于 alpha
预备阶段,但现在
象停止开发了。 字串1
SOAP.py 开发被冻结了。SOAP.py 这个项目是由 actzero 公司赞助
,而 actzero 却不再从事这一行业了。正在邀请自愿开发/维护 SOAP.py
组织。 字串2
soaplib
开发
象也延缓了,考虑到 Secret Labs 这段时间所承担
大量工作,或许就可以理解为什么会这样了。这个瑞典
公司是由 Fredrik Lundh 掌管
,他在 Python 圈内是出名
“工作狂”,同时也是 Python Association 董事会
一名成员。Secret Labs 还开发 PythonWare(Python
一个核心和重要
附加模块);PythonWorks(一个领先
Python IDE);Python Imaging Library 和许多其它
东西(日常 Python-URL Web 日志就是其中
一部分)。
Orchard 是一个数据管理框架,基本上是一种用一个公共接口管理不同数据格式
方法。它实现了一个 SOAP 客户机作为在远程过程调用中向 SOAP 服务器发送 Orchard 数据项
基本方法(被称为节点)。
字串7
PySOAP 这个项目主要是想作为 Dave Warner
Church 管理套件
一部分,但它还从没发行过任何文件,
象是一个毫无生气
项目。
安装
字串7
开始先下载分发包(在写这篇文章
时候,SOAPpy 0.9.7 是最新
分发包),把文件解包,转到结果目录,并把文件 SOAP.py复制到自己倾向
位置。当然,这个“倾向”就是需要技巧
地方。由于这些 SOAP lib 中有很多都使用大小写组合不同
“soap.py”作为模块名,所以大家一定要小心。当然,UNIX 用户只需关心大小写是否精确匹配,但对于 Windows 用户来说,甚至“SOAP.py”和“soap.py”之间
冲突也会带来麻烦。Orchard
SOAP.py 也有一个容易发生冲突
名称,但它有可能避开所有
问题,因为它
模块聪明地放在了 Orchard 包中。 字串4
上面
内容简言之就是建议您确保安装所有
Python SOAP 模块时都使用与众不同
包名称。在我们
案例中,我们在 PYTHONPATH 中发现了一个合适
目录并创建了一个 WebServices 包,把 SOAP.py 放在了这个包中。因此,在 Linux 中: 字串2
$ mkdir ~/lib/python/WebServices
$ touch ~/lib/python/WebServices/__init__.py
$ cp SOAPpy097/SOAP.py ~/lib/python/WebServices 字串1 字串9
请注意很重要
第二条命令,它将生成一个 __init__.py 文件,这个文件将 WebServices 目录标志为 Python 包。如果您需要把这些代码打包成 Windows 版本,您可能希望向空文件中输入一些注释,因为一些 Windows 工具不创建空文件。
您已深入主题了 字串4
对于公开提供
SOAP 服务器,早已经有了
几个活动
注册中心。最流行
可能是 XMethods。当然,它也是一个相当有趣
指导,通过它我们可以了解 SOAP
实际状况,而不要听它
吹嘘。这里
大多数公共 Web 服务仍然只是一些无关紧要
东西,几乎不值得我们勇敢
新模型多费口舌,但那是另一回事了。实际上,我们将选择一个公共服务来演示和测试如何把 SOAP.py 作为 SOAP 客户机使用。 字串2
或者,我们可以试试。作者尝试
第一个服务,卫生保健提供者定位器,在遇到下列报错消息时显示 SOAP 互操作性
当前状态中
陷阱:
字串9
WebServices.SOAP.faultType: Server did not recognize the value of
HTTP Header SOAPAction: "".> 字串3 哦。SOAPAction 是一个 HTTP 头,应该是用来标记被访问服务
。它是 SOAP 请求中必需
头,但即便是设置了所需
头(只是一对空
双引号)后,上面
错误仍然存在。作者发现大多数 MS SOAP 实现都存在这个问题。在试遍了这些服务后,我们断定,Delphi 实现
象与 SOAP.py 合作得最
,但在试服务时 — 即使是用 Delphi 实现时,也返回复杂
类型,比如列表,SOAP.py 无法使用它们,返回不带数据
WebServices.SOAP.typedArrayType 实例。
字串8
最后,作者选择了一个相当合适
Web 服务,该服务返回漫画《丁丁历险记》中
人物 Haddock 船长常用
骂人语言(是
,大多数 Web 服务都是这样)。 清单 1(curse.py)就是这个程序。
清单 1:访问 Curse 生成器 SOAP 服务
SOAP.py 程序 字串6
#!/usr/bin/env python
#http://xmethods.net/detail.html?id=175
import sys
#Import the SOAP.py machinery
from WebServices import SOAP
remote = SOAP.SOAPProxy(
"http://www.tankebolaget.se/scripts/Haddock.exe/soap/IHaddock",
namespace="urn:HaddockIntf-IHaddock",
soapaction="urn:HaddockIntf-IHaddock#Curse"
)
try:
lang = sys.argv[1]
except IndexError:
lang = "us"
result = remote.Curse(LangCode=lang)
print "What captain Haddock had to say: "%s""%result 字串7
字串9
把一切综合在一起
字串6
导入库后,我们将设置代理对象 remote 。这个对象将方法调用转换为远程 SOAP 消息。它
初始化器使用管理远程请求
关键参数:服务器
URI(被称为“端点”)、请求元素
XML 名称空间(通过它,SOAP-as-RPC 将口头承诺变成 XML 基础)和 SOAPAction 头值。
接下来,我们将确定方法参数,对于这个 Web 服务来说,方法参数只是 Haddock 骂人
语言,瑞典语(“se”)或英语(奇怪
是,是“us”而不是“en”)。
字串4
最后,我们调用名称正确
方法,代理对象
Curse 进行 SOAP 调用,然后打印出结果。下面
会话演示了对该程序
使用: 字串8
$ python curse.py
What captain Haddock had to say: "Ectoplasmic Byproduct!" 字串7 我们自己
SOAP 服务器
字串2
用 SOAP.py 实现 SOAP 服务器相当容易。作为一个示例,我们将仿建字段,还要实现一个很常见
服务:一个程序,给出年份和月份,它将以字符串
形式打印出日历。它
程序服务器是 清单 2(calendar-ws.py)。
清单 2:实现日历服务器
SOAP.py 程序
#!/usr/bin/env python
import sys, calendar
#Import the SOAP.py machinery
from WebServices import SOAP
CAL_NS = "http://uche.ogbuji.net/eg/ws/simple-cal"
class Calendar:
def getMonth(self, year, month):
return calendar.month(year, month)
def getYear(self, year):
return calendar.calendar(year)
server = SOAP.SOAPServer(("localhost", 8888))
cal = Calendar()
server.registerObject(cal, CAL_NS)
print "Starting server..."
server.serve_forever() 字串6 进行过必要
导入后,我们为自己
服务器定义 SOAP 请求元素期望
名称空间( CAL_NS )。接下来我们定义实现所有方法
类,这些方法将被公开为 SOAP 方法。大家也可以把单个函数作为 SOAP 方法注册,但使用类方法是最灵活
,特别是当您想管理调用间
状态时。这个 Calendar 类定义了一个方法 getMonth ,该方法使用 Python
内置日历模块在文本表单中返回月度日历,同时它还定义了另一个返回整年日历
方法。 字串3
然后创建 SOAP 服务器框架
一个实例,这个实例还带有侦听端口 8888
指令。我们还必须创建 Calendar 类
一个实例,这个实例在下一行中被注册用来处理 SOAP 消息,同时为其指出相关
名称空间。最后,我们调用 serve_forever 方法,该方法直到进程终止才返回。 字串9
字串1
为运行服务器,请打开另一个命令 shell 并执行 python calendar-ws.py 。执行结束时使用 ctrl-C 杀死进程。 字串2
我们本来可以用也是用 SOAP.py 写
客户机测试服务器,但那太显而易见了。我们还是用低级 Python 编写客户机把 SOAP 响应作为 XML 字符串来构建,并发送一条 HTTP 消息。这个程序(testcal.py)在 清单 3中。
清单 3:用 Python 核心库写
访问日历服务
客户机 字串1
import sys, httplib
SERVER_ADDR = "127.0.0.1"
SERVER_PORT = 8888
CAL_NS = "http://uche.ogbuji.net/ws/eg/simple-cal"
BODY_TEMPLATE = """ xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:s="http://uche.ogbuji.net/eg/ws/simple-cal"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
>
%s
%s
"""
def GetMonth():
year = 2001
month = 12
body = BODY_TEMPLATE%(year, month)
blen = len(body)
requestor = httplib.HTTP(SERVER_ADDR, SERVER_PORT)
requestor.putrequest("POST", "cal-server")
requestor.putheader("Host", SERVER_ADDR)
requestor.putheader("Content-Type", "text/plain; charset="utf-8"") 字串5
requestor.putheader("Content-Length", str(blen))
requestor.putheader("SOAPAction", "http://uche.ogbuji.net/eg/ws/simple-car")
requestor.endheaders()
requestor.send(body)
(status_code, message, reply_headers) = requestor.getreply()
reply_body = requestor.getfile().read()
print "status code:", status_code
print "status message:", message
print "HTTP reply body:
", reply_body
if __name__ == "__main__":
GetMonth() 字串1
字串1
下面
会话演示了这个测试
运行情况。
$ python testcal.py
status code: 200
status message: OK
HTTP reply body:
xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SO
AP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
December 2001
Mo Tu We Th Fr Sa Su
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
字串3 仔细审查
字节 字串3
如果您查找行 self.debug = 0 并把“0”改为“1”(这是 SOAP.py 版本 0.9.7 中
第 210 行),有一件要注意
事情是您可以获得被交换
实际 SOAP 消息
详细信息和用于调试与跟踪
其它关键数据,这对您很有用。作为示例,下面提供了一个会话,它是打开了调试信息显示开关
以前
curses.py 程序
一个会话: 字串4
$ python curse.py
*** Outgoing HTTP headers **********************************************
POST /scripts/Haddock.exe/soap/IHaddock HTTP/1.0
Host: www.tankebolaget.se
User-agent: SOAP.py 0.9.7 (actzero.com)
Content-type: text/xml; charset="UTF-8"
Content-length: 523
SOAPAction: "urn:HaddockIntf-IHaddock#Curse"
************************************************************************
*** Outgoing SOAP ******************************************************
xmlns:xsd="http://www.w3.org/1999/XMLSchema" xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:SO
AP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
us
字串5
************************************************************************
*** Incoming HTTP headers **********************************************
HTTP/1.? 200 OK
Server: Microsoft-IIS/5.0
Date: Tue, 11 Sep 2001 16:40:19 GMT
Content-Type: text/xml
Content-Length: 528
Content:
************************************************************************
*** Incoming SOAP ******************************************************
ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/1999/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xml
soap.org/soap/encoding/">xsi:type="xsd:string">Anacoluthons! se> 字串6
************************************************************************
What captain Haddock had to say: "Anacoluthons!" 字串5
字串1
为进行比较,您可以在带有下列代码
旧
Python 脚本或程序中获得相同
信息: 字串4
import calendar
return calendar.month(2001, 10) 字串5 SOAP.py 总结 字串2
我们已经注意到了,虽然 SOAP.py
互操作性还存在一些问题,但可用
调试工具可望提供帮助 ― 这个专栏
一位作者 Mike Olson 是已经签约要帮助这个项目继续发展
开发者之一。我们将看一下另一个 Python SOAP 实现。
字串3
字串6![我要研发网[www.51dev.com]](/templets/images/toplogo.gif)
