在 GAE 上搭建 XML-RPC 服务

前些日子有人问Doodle是否支持Windows Live Writer,我只是回答了不支持而已。原因很简单,我的Windows XP很奇怪,几次装Live Writer都失败,对微软已经绝望了。

不过现在已经转移到Mac OS X上了,装软件没这么奇葩的兼容性问题,于是就研究起weblog publishing API来。

博客发布API大致有2类:一类是基于XML-RPC服务的,包括Blogger API、MetaWeblog API、MovableType API和WordPress API等;另一类则是Atom Publishing Protocol。

后者虽然技术上比前者强大,但较为复杂(例如认证是基于HTTP的认证机制),而且由于出现得较晚,支持它的也比较少。当然,对我来说更重要的是文档很难找,因为这个协议并不只用于blog。

比较了1天后还是选择了XML-RPC。简单来说,它就是用XML封装方法名和各个参数,POST给XML-RPC服务器,再由服务器返回XML封装的方法运行结果。至于各种API,实际上只是方法和参数的差异,原理都是一致的。

下面举个提供加法的XML-RPC例子。

先是客户端,它需要POST这样一个XML给HTTP服务器:其

<?xml version="1.0"?>
<methodCall>
    <methodName>add</methodName>
    <params>
        <param>
            <value><int>2</int></value>
        </param>
        <param>
            <value><int>3</int></value>
        </param>
    </params>
</methodCall>

中methodName是方法名,它还有2个参数,类型为int,值分别为2和3。至于可用的类型,可以参考维基百科的XML-RPC条目,我发现官方文档反而不全。

而服务器接到这个请求后,则应该找到add这个方法,计算出结果为5,然后输出这样一个XML:

<?xml version='1.0'?>
<methodResponse>
    <params>
        <param>
            <value><int>5</int></value>
        </param>
    </params>
</methodResponse>

虽然这是一个很简单的处理过程,不过和XML打交道都是很烦的,要去提取方法名和各种参数,还得构造一个XML,想起来就觉得繁琐。

好在搜索了一下,发现Python内置了关于XML-RPC的标准库(SimpleXMLRPCServer和xmlrpclib),顿时觉得Pythoner太幸福了。

这里我就以一个实现加减法的XML-RPC服务为例了。由于最终是搭建在Google App Engine上,所以并不能直接使用SimpleXMLRPCServer类,而是直接使用它的父类SimpleXMLRPCDispatcher。话说自带的文档里并没有提到这个玩意,我还是在Epydoc文档里找到的。而且这个文档也没什么用,最终还是直接看源码去了…

from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
from google.appengine.ext.webapp import util
import yui

class XMLRPCDispatcher(SimpleXMLRPCDispatcher):
    def __init__(self, funcs):
        SimpleXMLRPCDispatcher.__init__(self, True, 'utf-8')
        self.funcs = funcs
        self.register_introspection_functions()

dispatcher = XMLRPCDispatcher({
    'add': lambda x, y: x + y,
    'sub': lambda x, y: x - y
})

class RpcHandler(yui.RequestHandler):
    def post(self):
        self.set_content_type('text/xml')
        response = dispatcher._marshaled_dispatch(self.request.body)
        self.write(response)

application = yui.WsgiApplication([
    ('/rpc', RpcHandler)
])

def main():
    util.run_wsgi_app(application)

if __name__ == '__main__':
    main()

SimpleXMLRPCDispatcher对象的__init__()方法接收3个参数,第2个是方法名中是否允许带“.”号,第3个则是编码了。

它的funcs属性是个字典,也就是方法名和方法之间的映射。

它的register_introspection_functions()方法则是根据funcs属性里的方法来生成system.listMethods、system.methodSignature和system.methodHelp这3个方法,主要就是对外公布自己可以提供哪些方法。

初始化并设置完它的方法后,就可以调用它的_marshaled_dispatch()方法了。这个方法接收一个XML字符串参数,自动解析并运行对应的方法,然后再把结果封装成XML返回。于是就可以不用直接和讨厌的XML打交道了~

服务端做好后就可以用客户端来测试了,这玩意就更简单了。构造一个xmlrpclib.Server对象,然后直接调用它的方法即可:

import xmlrpclib
s = xmlrpclib.Server('http://localhost:8080/rpc')
print s.add(2, 3)
print s.sub(5, 2)
print s.system.listMethods()

要注意的是,构造Server对象时,如果没给出路径,默认的路径并不是"/",而是"/RPC2"。

而如上所述,system.listMethods()方法是由register_introspection_functions()方法自动生成的,用于列出所有方法。

最终结果如下:

5
3
['add', 'sub', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']

最后顺带一提,上面提到的博客发布API中,我觉得最简洁的是MetaWeblog API,不过缺了删除日志和列出标签的API;WordPress API是最丰富的,可惜很多功能用不上。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。