soap¶
Uliweb 为了支持soap的处理,提供了 uliweb.contrib.soap app。它依赖于以下模块:
- pysimplesoap
目前已经内置在uliweb/lib下了,不过这个版本做了一些改动,所以不能简单地使用 原来的包进行处理。主要改动是对SoapDispatcher类的,一方面可以在构造函数中可 以传入自定义的exception处理,另一方面是在dispatch()方法中添加了call_function 参数,以便对方法调用进行封装。
- suds
这个可以用来做为客户端的使用。不过uliweb中并没有内置它,需要自行安装。也可 以使用pysimplesoap带的client类。通过导入:
from uliweb.lib.pysimplesoap.client import SoapClient
不过目前感觉还有一些问题。
- httplib2 或 pycurl
用于pysimplesoap的客户端处理。
配置说明¶
使用soap服务,首先要在settings.ini中安装uliweb.contrib.soap。例如:
[GLOBAL]
INSTALLED_APPS = [
...
'uliweb.contrib.soap',
...
]
同时 uliweb.contrib.soap 的settings.ini下已经预设了一些配置项,用户可以根据需要 进行覆盖,如:
[DECORATORS]
soap = 'uliweb.contrib.soap.soap'
[EXPOSES]
soap_url = '/SOAP', 'uliweb.contrib.soap.views.soap'
[SOAP]
namespace = None
documentation = 'Uliweb Soap Service'
name = 'UliwebSoap'
prefix = 'pys'
首先它定义了一个soap的decorator,因此用户后面可以使用Decorators.soap来使用它, 后面会详细说明。
然后在EXPOSES中定义了外部访问时使用的URL,缺省为 '/SOAP'
。你可以根据需要进行 重定义。
然后是soap服务相关的一些描述信息。
- namespace
用来指明服务内部定义的一些名字空间的说明地址,缺省为None,表示和服务的URL是 一个地址。
- documentation
服务的说明信息。
- name
service的名字
- prefix
名字空间的前缀,缺省为 'pys'。
View的定义¶
服务已经安装好了,下面是定义相关的处理函数。通常你仍然可以定义在views.py中。但是 要注意,这里我们并不使用@expose来处理,而是使用@soap来处理,但是它仍然有view一样 的特性。不过,返回的内容不是HTML而是XML。
举例如下:
from uliweb import decorators
from uliweb.contrib.soap import Date, DateTime, Decimal
@decorators.soap('hello', returns={'a':str}, args={'a':str})
def hello(a):
return 'Hello:' + a
在pysimplesoap中定义了一些类型,用来描述数据类型的,uliweb已经将其导到 uliweb.contrib.soap 中,因此可以直接从这里导入。pysimplesoap采用内置类型和自定义类型相结合的方式, 比如常见的有:
int, str, float, unicode, bool, short, byte, long,
integer, decimal, dateTime, date
因此,对于服务描述使用的wsdl,采用自动生成的方式。
在上面的例子中,使用@decorators.soap来定义一个soap服务。其中soap方法接受以下参 数:
- name
方法名,如果没有给出,则会自动将所修饰的函数名作为方法名。同时支持类方法的 方式。
- returns
返回值描述。它是一个字典,可以进行嵌套描述。上例表示,返回值为一个简单 类型,tag名为'a',值是'string'类型。缺省为None。
- args
输入参数描述。它也是一个字典,定义方式同returns。缺省为None。如果为None,则 表示缺省为一个参数,可以是任意类型。
- doc
方法描述说明。缺省为None。
因此在上例中,在soap中定义了三个参数:
name = 'hello'
returns = {'a':str}
args = {'a':str}
所以这个soap方法的名字叫 'hello'。
soap的下面为所修饰的函数。这里正好为hello,也可以为别的。它需要定义一个参数,名 为 'a',与args中的定义要一致。
返回值直接为一个字符串。在返回时会自动对它进行封装。
类型描述说明¶
类型描述就是针对returns和args的声明使用的。它支持简单类型手复杂类型。复杂类型 一般指:数组和字典。
当只有一个返回值时,一般定义为:
{'name':type}
这里type可以是前面说过的对象,如: int, str等。如果只有一个值,一般soap函数直接 返回就可以了,不必是一个字典的形式。
如果是多个值,一般定义为:
{'name1':type1, 'name2':type2}
定义为字典的形式。返回时应按说明返回一个字典。
如果是一个数组,一般定义为:
{'name':[type]}
{'name':{'sub_name':type}}
有两种定义方式。第一种会自动转換为第二种形式。但是sub_name的名字是根据type的名 字自动生成的。所以:
{'name':[int]}
其实就是:
{'name':{'int':int}}
以上几种数据定义方式可以嵌套使用,从而形成更复杂的数据格式定义。
更复杂的一些示例¶
这个例子实现将上传的整数数组相加后返回:
@decorators.soap(returns={'a':int}, args={'a':[int]})
def add(a):
t = 0
for x in a:
t += x['int']
return t
这里a其实形式为: [{'int':v1}, {'int':v2}]
这个示例实现将上传字符串数组统一在后面添加 '中文' 信息:
@decorators.soap(returns={'a':[str]}, args={'a':[str]})
def string(a):
t = []
for i, x in enumerate(a):
t.append(x['string'] + u'中文')
return t
建议使用unicode进行中文处理。返回仍是一个数组。
客户端示例¶
以下以suds作为客户端来演示如何访问soap服务。以hello为例,首先准备一个服务端代码。 在某个app中的views.py中添加如下代码:
from uliweb import decorators
from uliweb.contrib.soap import Date, DateTime, Decimal
@decorators.soap('hello', returns={'a':str}, args={'a':str})
def hello(a):
return 'Hello:' + a
然后启动服务器,等待测试。
创建一个客户端的测试文件,写入如下代码:
#coding=utf8
#import logging
#logging.basicConfig()
#logging.getLogger('suds.client').setLevel(logging.DEBUG)
from suds.client import Client
client = Client('http://localhost:8000/SOAP?wsdl')
print client
result = client.service.hello('limodou')
print 'test1:', result
前几行是用来控制日志输出的。suds提供debug状态,可以根据程序处理的中间结果。这里 我已经注释掉了,你可以根据需要来使用。
首先是创建一个Client,只要传入一个wsdl的地址。这个地址就是前面的soap_url加上 ?wsdl
。
然后我们可以打印看一下这个client是什么东西:
Suds ( https://fedorahosted.org/suds/ ) version: 0.4 GA build: R699-20100913
Service ( UliwebSoapService ) tns="http://localhost:8000/SOAP"
Prefixes (0)
Ports (1):
(UliwebSoap)
Methods (1):
hello(xs:string a, )
Types (0):
可以看到我们定义的web service的一些信息,如有什么方法,需要什么参数等。
然后通过 client.service.hello('limodou') 来调用服务,结果会是:
test1: Hello:limodou
更详细的示例,可以参考 uliweb-doc/projects/uliweb/soap_test 中的代码。
另,通过设置apps/settings.ini:
[LOG] level = 'debug'
也可以看到后台在接收和发送应答时的XML信息。