soap.py 包含的是一些基本的东西。没有 web 服务描述语言(web services description language,wsdl)或者任何其它附加的东西,只有用 python 实现的 soap 客户机和服务器的透明支持。甚至这个包中的一个很好的功能也只是与基础架构相关:soap.py 支持安全套接字层(ssl)用于加密的 soap 传输。为使用这个功能,您必须安装 m2crypto,m2crypto 是一个库,包含各种加密工具和格式,从 rsa 和 dsa 到 https、s/mime 等等。在这一部分,我们不准备讨论 soap.py 的 ssl 支持。
soap 操作摘要
目前为止,soap 实用程序好象仍是比较流行的使用 python 的开放源代码活动。下面是该项目的纲要以及它们目前的状态。首先,参与者:
4suite soap,由 fourthought 管理 soapy,由 adam elman 管理 soap.py,python 项目的一个 web 服务项目 soaplib,由 secret labs 管理 orchard,由 ken macleod 管理 pysoap,由 dave warner 管理4suite soap 是我们自己的实现,我们在本专栏的前面三部分中使用过(请参阅 参考资料以获得它的链接)。它目前仍在开发中。
soapy 是在 2001 年 4 月公布的,目前处于 alpha 的预备阶段,但现在好象停止开发了。
soap.py 开发被冻结了。soap.py 这个项目是由 actzero 公司赞助的,而 actzero 却不再从事这一行业了。正在邀请自愿开发/维护 soap.py 的组织。
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 数据项的基本方法(被称为节点)。
pysoap 这个项目主要是想作为 dave warner 的 church 管理套件的一部分,但它还从没发行过任何文件,好象是一个毫无生气的项目。
安装
开始先下载分发包(在写这篇文章的时候,soappy 0.9.7 是最新的分发包),把文件解包,转到结果目录,并把文件 soap.py复制到自己倾向的位置。当然,这个“倾向”就是需要技巧的地方。由于这些 soap lib 中有很多都使用大小写组合不同的“soap.py”作为模块名,所以大家一定要小心。当然,unix 用户只需关心大小写是否精确匹配,但对于 windows 用户来说,甚至“soap.py”和“soap.py”之间的冲突也会带来麻烦。orchard 的 soap.py 也有一个容易发生冲突的名称,但它有可能避开所有的问题,因为它的模块聪明地放在了 orchard 包中。
上面的内容简言之就是建议您确保安装所有的 python soap 模块时都使用与众不同的包名称。在我们的案例中,我们在 pythonpath 中发现了一个合适的目录并创建了一个 webservices 包,把 soap.py 放在了这个包中。因此,在 linux 中:
$ mkdir ~/lib/python/webservices$ touch ~/lib/python/webservices/__init__.py$ cp soappy097/soap.py ~/lib/python/webservices
请注意很重要的第二条命令,它将生成一个 __init__.py 文件,这个文件将 webservices 目录标志为 python 包。如果您需要把这些代码打包成 windows 版本,您可能希望向空文件中输入一些注释,因为一些 windows 工具不创建空文件。
您已深入主题了
对于公开提供的 soap 服务器,早已经有了好几个活动的注册中心。最流行的可能是 xmethods。当然,它也是一个相当有趣的指导,通过它我们可以了解 soap 的实际状况,而不要听它的吹嘘。这里的大多数公共 web 服务仍然只是一些无关紧要的东西,几乎不值得我们勇敢的新模型多费口舌,但那是另一回事了。实际上,我们将选择一个公共服务来演示和测试如何把 soap.py 作为 soap 客户机使用。
或者,我们可以试试。作者尝试的第一个服务,卫生保健提供者定位器,在遇到下列报错消息时显示 soap 互操作性的当前状态中的陷阱:
webservices.soap.faulttype:
哦。soapaction 是一个 http 头,应该是用来标记被访问服务的。它是 soap 请求中必需的头,但即便是设置了所需的头(只是一对空的双引号)后,上面的错误仍然存在。作者发现大多数 ms soap 实现都存在这个问题。在试遍了这些服务后,我们断定,delphi 实现好象与 soap.py 合作得最好,但在试服务时 — 即使是用 delphi 实现时,也返回复杂的类型,比如列表,soap.py 无法使用它们,返回不带数据的 webservices.soap.typedarraytype 实例。
最后,作者选择了一个相当合适的 web 服务,该服务返回漫画《丁丁历险记》中的人物 haddock 船长常用的骂人语言(是的,大多数 web 服务都是这样)。 清单 1(curse.py)就是这个程序。
清单 1:访问 curse 生成器 soap 服务的 soap.py 程序
#!/usr/bin/env python#http://xmethods.net/detail.html?id=175import sys#import the soap.py machineryfrom webservices import soapremote = 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 = usresult = remote.curse(langcode=lang)print what captain haddock had to say: %s%result
把一切综合在一起
导入库后,我们将设置代理对象 remote 。这个对象将方法调用转换为远程 soap 消息。它的初始化器使用管理远程请求的关键参数: 服务器的 uri(被称为“端点”)、请求元素的 xml 名称空间(通过它,soap-as-rpc 将 口头承诺变成 xml 基础)和 soapaction 头值。
接下来,我们将确定方法参数,对于这个 web 服务来说,方法参数只是 haddock 骂人的语言,瑞典语(“se”)或英语(奇怪的是,是“us”而不是“en”)。
最后,我们调用名称正确的方法,代理对象的 curse 进行 soap 调用,然后打印出结果。下面的会话演示了对该程序的使用:
$ python curse.pywhat captain haddock had to say: ectoplasmic byproduct!
我们自己的 soap 服务器
用 soap.py 实现 soap 服务器相当容易。作为一个示例,我们将仿建字段,还要实现一个很常见的服务:一个程序,给出年份和月份,它将以字符串的形式打印出日历。它的程序服务器是 清单 2(calendar-ws.py)。
清单 2:实现日历服务器的 soap.py 程序
#!/usr/bin/env pythonimport sys, calendar#import the soap.py machineryfrom webservices import soapcal_ns = http://uche.ogbuji.net/eg/ws/simple-calclass 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()
进行过必要的导入后,我们为自己的服务器定义 soap 请求元素期望的名称空间( cal_ns )。接下来我们定义实现所有方法的类,这些方法将被公开为 soap 方法。大家也可以把单个函数作为 soap 方法注册,但使用类方法是最灵活的,特别是当您想管理调用间的状态时。这个 calendar 类定义了一个方法 getmonth ,该方法使用 python 的内置日历模块在文本表单中返回月度日历,同时它还定义了另一个返回整年日历的方法。
然后创建 soap 服务器框架的一个实例,这个实例还带有侦听端口 8888 的指令。我们还必须创建 calendar 类的一个实例,这个实例在下一行中被注册用来处理 soap 消息,同时为其指出相关的名称空间。最后,我们调用 serve_forever 方法,该方法直到进程终止才返回。
为运行服务器,请打开另一个命令 shell 并执行 python calendar-ws.py 。执行结束时使用 ctrl-c 杀死进程。
我们本来可以用也是用 soap.py 写的客户机测试服务器,但那太显而易见了。我们还是用低级 python 编写客户机把 soap 响应作为 xml 字符串来构建,并发送一条 http 消息。这个程序(testcal.py)在 清单 3中。
清单 3:用 python 核心库写的访问日历服务的客户机
import sys, httplibserver_addr = 127.0.0.1server_port = 8888cal_ns = http://uche.ogbuji.net/ws/eg/simple-calbody_template = %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) requestor.putheader(content reply_body = requestor.getfi-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()le().read() print status code:, status_code print status message:, message print http reply body:\n, reply_bodyif __name__ == __main__: getmonth()
下面的会话演示了这个测试的运行情况。
$ python testcal.pystatus code: 200status message: okhttp reply body: december 2001mo tu we th fr sa su 1 2 3 4 5 6 7 8 910 11 12 13 14 15 1617 18 19 20 21 22 2324 25 26 27 28 29 3031
仔细审查的字节
如果您查找行 self.debug = 0 并把“0”改为“1”(这是 soap.py 版本 0.9.7 中的第 210 行),有一件要注意的事情是您可以获得被交换的实际 soap 消息的详细信息和用于调试与跟踪的其它关键数据,这对您很有用。作为示例,下面提供了一个会话,它是打开了调试信息显示开关的以前的 curses.py 程序的一个会话:
$ python curse.py *** outgoing http headers **********************************************post /scripts/haddock.exe/soap/ihaddock http/1.0host: www.tankebolaget.seuser-agent: soap.py 0.9.7 (actzero.com)content-type: text/xml; charset=utf-8content-length: 523soapaction: urn:haddockintf-ihaddock#curse*************************************************************************** outgoing soap ******************************************************us*************************************************************************** incoming http headers **********************************************http/1.? 200 okserver: microsoft-iis/5.0date: tue, 11 sep 2001 16:40:19 gmtcontent-type: text/xmlcontent-length: 528content:*************************************************************************** incoming soap ******************************************************anacoluthons!************************************************************************what captain haddock had to say: anacoluthons!
为进行比较,您可以在带有下列代码的旧的 python 脚本或程序中获得相同的信息:
import calendarreturn calendar.month(2001, 10)
soap.py 总结
我们已经注意到了,虽然 soap.py 的互操作性还存在一些问题,但可用的调试工具可望提供帮助。
