python suds zeep api
python soap协议库 zeep 各种问题解决方法 https://woj.app/4723.html
Suds是一个轻量级的SOAP python客户端,它为Web服务提供服务代理。
概述
suds的目标是在基于SOAP的Web服务中提供类似RPC的接口。这意味着在大多数情况下,用户不需要关心WSDL和引用模式的复杂性。无论指定哪种soap消息样式,服务方法的签名都保持不变。检查WSDL的用户会注意到,即使使用'document'肥皂消息样式,每个方法的签名也类似于RPC。方法签名包含为消息定义的“文档”的内容,而不是文档本身。
基本功能:
- 没有一代人
- 提供类似对象的API。
- 在运行时读取wsdl以进行编码/解码
-
- 提供以下SOAP(样式)绑定/编码:
-
- 文档/文字
- RPC /文字
- RPC /编码(第5节)
suds的目标是在基于SOAP的Web服务中提供类似RPC的接口。这意味着在大多数情况下,用户不需要关心WSDL和引用模式的复杂性。无论指定哪种soap消息样式,服务方法的签名都保持不变。检查WSDL的用户会注意到,即使使用'document'肥皂消息样式,每个方法的签名也类似于RPC。方法签名包含为消息定义的“文档”的内容,而不是文档本身。
记录
'suds'包使用Python标准的lib日志包,所有消息都在DEBUG或ERROR级别。
要注册控制台处理程序,您可以使用basicConfig:
#!python
import logging
logging.basicConfig(level=logging.INFO)
配置控制台处理程序后,用户可以启用特定于模块的调试,执行以下操作:
logging.getLogger(<desired package>).setLevel(logging.<desired-level>)
一个常见示例(显示发送/接收的肥皂消息):
#!python
logging.getLogger('suds.client').setLevel(logging.DEBUG)
建议的调试模块:
suds.client:
在此模块上将日志记录级别设置为“DEBUG”以查看soap消息(输入和输出)和http标头。
suds.transport:
在此模块上将日志记录级别设置为“DEBUG”,以查看有关soap消息(输入和输出)和http标头的更多详细信息。
suds.xsdschema:
在此模块上将日志记录级别设置为“DEBUG”以查看模式的消化。
suds.wsdl:
在此模块上将日志记录级别设置为“DEBUG”以查看消化WSDL。
基本用法
'suds'[suds.client.Client-class.html Client]类提供了一个用于使用Web服务的统一API。该对象包含(2)子命名空间:
服务:
[suds.client.Service-class.html service]命名空间为使用的服务提供代理。此对象用于调用服务端点提供的操作(方法)。
工厂:
[suds.client.Factory-class.html factory]命名空间提供了一个工厂,可用于创建WSDL中定义的对象和类型的实例。
您需要知道所使用的每个服务的WSDL URL。只需为该服务创建一个客户端,如下所示:
#!python
from suds.client import Client
url = 'http://localhost:7080/webservices/WebServiceTestBean?wsdl'
client = Client(url)
您可以使用__str__()
以下方法检查服务对象:获取服务提供的方法列表:
#!python
print client
Suds - version: 1.3.3.1 build: IN 20180220
Service (WebServiceTestBeanService) tns="http://test.server.enterprise.rhq.org/"
Prefixes (1):
ns0 = "http://test.server.enterprise.rhq.org/"
Ports (1):
(Soap)
Methods:
addPerson(Person person, )
echo(xs:string arg0, )
getList(xs:string str, xs:int length, )
getPercentBodyFat(xs:string name, xs:int height, xs:int weight)
getPersonByName(Name name, )
hello()
testExceptions()
testListArg(xs:string[] list, )
testVoid()
updatePerson(AnotherPerson person, name name, )
Types (23):
Person
Name
Phone
AnotherPerson
注意
请参阅下面的多个端口的服务示例。
示例输出列出了名为的服务WebServiceTestBeanService
具有getPercentBodyFat()
和等方法addPerson()
。
简单参数
让我们从简单的例子开始吧。该getPercentBodyFat()
方法具有签名。在这种情况下,参数是“简单”类型。也就是说,它们不是对象。此方法将按如下方式调用:getPercentBodyFat('xs:string' name, 'xs:int' height, 'xs:int' weight)
#!python
result = client.service.getPercentBodyFat('jeff', 68, 170)
print result
You have 21% body fat.
#!python
result = client.service.getPercentBodyFat(name='jeff', height=68, weight=170)
print result
You have 21% body fat.
#!python
d = dict(name='jeff', height=68, weight=170)
result = client.service.getPercentBodyFat(**d)
print result
You have 21% body fat.
复杂的参数
该addPerson()
方法采用类型为'Person'的'person'参数,并具有以下签名: 其中打印参数类型,后跟其名称。addPerson('Person' person, )
有一个名为'person'的类型(或类),其巧合的名称与参数相同。或在的情况下getPercentBodyFat()
的参数是字符串类型的xs:字符串和整数类型的xs:INT。
因此,要创建一个'Person'对象作为参数传递,我们需要使用'factory'子命名空间获取一个person参数,如下所示:
#!python
person = client.factory.create('Person')
print person
(Person)=
{
phone = []
age = NONE
name(Name) =
{
last = NONE
first = NONE
}
}
如您所见,该对象是按WSDL定义创建的。电话号码列表为空,因此我们必须创建一个“电话”对象:
#!python
phone = client.factory.create('Phone')
phone.npa = 202
phone.nxx = 555
phone.number = 1212
...并且需要设置名称(Name对象)和age,我们需要首先创建一个名称对象:
#!python
name = client.factory.create('Name')
name.first = 'Elmer'
name.last = 'Fudd'
现在,让我们设置'Person'对象的属性:
#!python
person.name = name
person.age = 35
person.phone = [phone]
要么:
#!python
person.phone.append(phone)
...并调用我们的方法,命名addPerson()
如下:
#!python
try:
person_added = client.service.addPerson(person)
except WebFault, e:
print e
就这么简单。
当用户是wsdl / schema中定义的类型的子类(或扩展)时,用户可能不会对复杂对象使用python'dict'。换句话说,如果架构将类型定义为“动物”并且您希望传递“狗”(假设狗'isa'动物),则您可能不会使用'dict'来表示狗。在这种情况下,suds需要设置xsi:type =“Dog”但不能,因为python'dict'没有提供足够的信息来表明它是'Dog'而不是'Animal'。最有可能的是,服务器将拒绝该请求并指示它无法实例化抽象的“动物”。
使用Python的复杂参数(dict)
就像工厂示例一样,我们假设该addPerson()
方法采用类型为'Person'的'person'参数。因此,要创建一个'Person'对象作为参数传递,我们需要获取一个person对象,我们可以通过创建一个简单的python'dict'来实现:
#!python
person = {}
根据WSDL,我们知道Person包含一个Phone对象列表,所以我们也需要'dict'代码:
#!python
phone = {
'npa':202,
'nxx':555,
'number':1212,
}
...并且需要设置名称(Name对象)和age,我们需要首先创建一个名称对象:
#!python
name = {
'first':'Elmer',
'last':'Fudd'
}
现在,让我们设置'Person'对象的属性:
#!python
person['name'] = name
person['age'] = 35
person['phone'] = [phone,]
...并调用我们的方法,命名addPerson()
如下:
#!python
try:
person_added = client.service.addPerson(person)
except WebFault, e:
print e
}}}
错误
可以将客户端配置为抛出Web故障,WebFault
或者返回元组,如下所示:(<status>,<returned-value>)
#!python
client = client(url, faults=False)
result = client.service.addPerson(person)
print result
( 200, person ...)
选项
'suds'[suds.client.Client-class.html客户端]有很多可用于控制库行为的东西。一些是[suds.options.Options-class.html一般选项],另一些是[suds.transport.options.Options-class.html transport options]。虽然公开了选项对象,但是设置/取消设置选项的首选和支持方式是通过
- [suds.client.Client-class.html Client]构造函数
- [suds.client.Client-class.html客户端] .set_options()
- [suds.transport.Transport-class.html Transport]构造函数。
它们如下:
faults:
控制Web故障行为。
service:
控制多服务wsdls的默认服务名称。
port:
控制多端口服务的默认服务端口。
location:
这将覆盖WSDL中定义的服务端口地址“URL”。
proxy:
控制http代理设置。
transport:
控制'插件'网页[suds.transport.Transport-class.html transport]。
cache:
提供与加载WSDL相关的文档和对象的缓存。肥皂信封永远不会被缓存。
cachingpolicy:
缓存策略确定如何缓存数据。默认值为0。
- 0 = XML文档,如WSDL和XSD。
- 1 = WSDL对象图。
headers:
提供“额外”的http标头。
soapheaders:
提供肥皂标题。
wsse:
提供WS-Security对象。
__inject:
控制消息/回复消息注入。
doctor:
模式'doctor'指定用于修复损坏模式的对象。
xstq:
'X'ML's'sche''t'type'q'ualified标志表示'xsi:type'属性值应该由命名空间限定。
prefixes:
soap消息的元素应该使用XML前缀限定(在需要时),而不是xmlns =“”语法。
timeout:
URL连接超时(秒)默认= 90。
retxml:
导致返回I {raw} soap信封而不是python对象图的标志。
autoblend:
确保WSDL中定义的模式相互导入的标志。
nosend:
导致肥皂泡生成肥皂信封但不发送的标志。相反,返回[suds.client.RequestContext-class.html RequestContext]默认值:False。
枚举
枚举处理如下
假设wsdl定义了以下枚举:
#!xml
<xs:simpleType name="resourceCategory">
<xs:restriction base="xs:string">
<xs:enumeration value="PLATFORM"/>
<xs:enumeration value="SERVER"/>
<xs:enumeration value="SERVICE"/>
</xs:restriction>
</xs:simpleType>
客户端可以实例化枚举,以便可以使用它。
对'enum'元素的拼错引用会引发AttrError
异常,如下所示:
#!python
resourceCategory = client.factory.create('resourceCategory')
client.service.getResourceByCategory(resourceCategory.PLATFORM)
工厂
[suds.client.Factory-class.html factory]用于创建定义wsdl / schema的复杂对象。对于指定为“简单”类型的参数或类型,例如xs:string,xs:int等,这不是必需的...
create()
应始终使用该方法,因为它返回已具有正确结构和模式类型信息的对象。由于xsd支持嵌套类型定义,因此create()
使用(.)
点表示法也是如此。例如,假设(Name)
类型未定义为顶级“命名”类型,而是在(Person)类型中定义。在这种情况下,创建(Name)
对象必须使用点符号通过其父级名称进行限定,如下所示:
#!python
name = client.factory.create('Person.Name')
如果类型与wsdl位于相同的名称空间中,(targetNamespace)
则可以在没有任何名称空间限定的情况下引用它。如果不是,则必须使用名称空间前缀来限定类型,例如:
#!python
name = client.factory.create('ns0:Person')
或者,名称可以由命名空间本身使用完全限定语法完全限定:
#!python
name = client.factory.create('{http://test.server.enterprise.rhq.org/}person')
当使用(.)
点表示法指定路径时,限定名称只能用于名称的“第一”部分。
多端口服务
某些服务定义为多个端口:
#!xml
<wsdl:service name="BLZService">
<wsdl:port name="soap" binding="tns:BLZServiceSOAP11Binding">
<soap:address location="http://www.thomas-bayer.com:80/axis2/services/BLZService"/>
</wsdl:port>
<wsdl:port name="soap12" binding="tns:BLZServiceSOAP12Binding">
<soap12:address location="http://www.thomas-bayer.com:80/axis2/services/BLZService"/>
</wsdl:service>
肥皂水报道:
#!python
url = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl'
client = Client(url)
print client
Suds - version: 1.3.3.1 build: IN 20180220
Service (BLZService) tns="http://thomas-bayer.com/blz/"
Prefixes (1)
ns0 = "http://thomas-bayer.com/blz/"
Ports (2):
(soap)
Methods (1):
getBank(xs:string blz, )
(soap12)
Methods (1):
getBank(xs:string blz, )
Types (5):
getBankType
getBankResponseType
getBankType
getBankResponseType
detailsType
此示例仅为每个端口定义了(1)方法,但很可能定义了may方法。Suds不要求方法调用由端口限定(如上所示):
#!python
client.service.<port>.getBank()
除非用户想要指定特定端口。在大多数情况下,服务器将与任何soap端口一起正常工作。但是,如果要在此服务上调用getBank()方法,则用户可以使用该端口限定方法名称。
有两种方法可以做到这一点:
-
在调用方法之前,使用'port'[suds.options.Options-class.html选项]选择默认端口:
#!python client.set_options(port='soap') client.service.getBank()
-
将方法完全限定为:
#!python client.service.soap.getBank()
在(1)WSDL中支持多服务,如下所示:
此示例仅为每个端口定义了(1)方法,但很可能定义了may方法。Suds不要求方法调用由端口限定(如上所示):
#!python
client.service[port].getBank()
除非用户想要指定特定端口。在大多数情况下,服务器将与任何soap端口一起正常工作。但是,如果要getBank()
在此服务上调用 方法,则用户可以使用端口限定方法名称。'port'可以通过name(string)或index(int)订阅。
有很多方法可以做到这一点:
-
在调用方法之前,使用'port'[suds.options.Options-class.html选项]选择默认端口:
#!python client.set_options(port='soap') client.service.getBank()
-
使用端口'name'完全限定方法:
#!python client.service['soap'].getBank()
-
使用端口'index'完全限定方法为:
#!python client.service[0].getBank()
具有多个服务和多个端口的
一些WSDL定义了多个服务,这些服务可能(或可能不)使用多个端口定义为:
#!xml
<wsdl:service name="BLZService">
<wsdl:port name="soap" binding="tns:BLZServiceSOAP11Binding">
<soap:address location="http://www.thomas-bayer.com:80/axis2/services/BLZService"/>
</wsdl:port>
<wsdl:port name="soap12" binding="tns:BLZServiceSOAP12Binding">
<soap12:address location="http://www.thomas-bayer.com:80/axis2/services/BLZService"/>
</wsdl:service>
<wsdl:service name="OtherBLZService">
<wsdl:port name="soap" binding="tns:OtherBLZServiceSOAP11Binding">
<soap:address location="http://www.thomas-bayer.com:80/axis2/services/OtherBLZService"/>
</wsdl:port>
<wsdl:port name="soap12" binding="tns:OtherBLZServiceSOAP12Binding">
<soap12:address location="http://www.thomas-bayer.com:80/axis2/services/OtherBLZService"/>
</wsdl:service>
肥皂水报道:
#!python
url = 'http://www.thomas-bayer.com/axis2/services/BLZService?wsdl'
client = Client(url)
print client
Suds - version: 1.3.3.1 build: IN 20180220
Service (BLZService) tns="http://thomas-bayer.com/blz/"
Prefixes (1)
ns0 = "http://thomas-bayer.com/blz/"
Ports (2):
(soap)
Methods (1):
getBank(xs:string blz, )
(soap12)
Methods (1):
getBank(xs:string blz, )
Types (5):
getBankType
getBankResponseType
getBankType
getBankResponseType
detailsType
Service (OtherBLZService) tns="http://thomas-bayer.com/blz/"
Prefixes (1)
ns0 = "http://thomas-bayer.com/blz/"
Ports (2):
(soap)
Methods (1):
getBank(xs:string blz, )
(soap12)
Methods (1):
getBank(xs:string blz, )
Types (5):
getBankType
getBankResponseType
getBankType
getBankResponseType
detailsType
此示例仅为每个端口定义了(1)方法,但很可能定义了may方法。泡沫不会不要求方法调用被组队参加(如上所示)由服务和/或端口为:
#!python
client.service[service][port].getBank()
除非用户想要指定特定服务和/或端口。在大多数情况下,服务器将与任何soap端口一起正常工作。但是,如果要getBank()
在OtherBLZService
服务上调用方法,则用户可以使用服务和/或端口限定方法名称。如果未指定,suds将服务默认为WSDL中定义的第一个服务器,并默认为每个服务中的第一个端口。此外,当WSDL定义(1)服务时,[]下标应用于端口选择。这可能有点令人困惑,因为下标的语法似乎不一致。
'service' 和 'port'都可以通过name(string)或index(int)来下标。
有很多方法可以做到这一点:
-
在调用方法之前,使用'service'选项和默认端口使用'port'选项[suds.options.Options-class.html选项]选择默认服务:
#!python client.set_options(service='OtherBLZService', port='soap') client.service.getBank()
-
'service'和'port'限定的方法为:
#!python client.service['OtherBLZService']['soap'].getBank()
-
'service'和'port'使用索引限定的方法:
#!python client.service[1][0].getBank()
-
'service'(按名称)限定的方法仅作为:
#!python client.service['OtherBLZService'].getBank()
-
'service'(索引)限定的方法仅作为:
#!python client.service[1].getBank()
注意,如果WSDL定义了多个服务,则必须通过[suds.options.Options-class.html选项]或使用下标语法限定'service',以便使用下标语法指定'port' 。
SOAP标头
可以在服务调用期间使用'soapheaders'[suds.options.Options-class.html选项]传递SOAP标头,如下所示:
#!python
client = client(url)
token = client.factory.create('AuthToken')
token.username = 'Elvis'
token.password = 'TheKing'
client.set_options(soapheaders=token)
result = client.service.addPerson(person)
要么:
#!python
client = client(url)
userid = client.factory.create('Auth.UserID')
userid.set('Elvis')
password = client.factory.create('Auth.Password')
password.set('TheKing')
client.set_options(soapheaders=(userid,password))
result = client.service.addPerson(person)
要么:
#!python
client = client(url)
userid = 'Elmer'
passwd = 'Fudd'
client.set_options(soapheaders=(userid,password))
result = client.service.addPerson(person)
当指定可选标题并且用户不想传递无占位符时,也可以为“soapheaders”选项分配字典。这与方法参数非常相似。例如:
#!python
client = client(url)
myheaders = dict(userid='Elmer', passwd='Fudd')
client.set_options(soapheaders=myheaders)
result = client.service.addPerson(person)
自定义SOAP标头
可以在服务调用期间使用'soapheaders'[suds.options.Options-class.html选项]传递自定义SOAP标头。“自定义”soap标头定义为服务所需的标头,未在wsdl中定义。因此,不能使用已经描述的传递肥皂头的“简单”方法。这是通过构造和传递[suds.sax.element.Element-class.html Element]或[suds.sax.element.Element-class.html Elements]的集合来完成的,如下所示:
#!python
from suds.sax.element import Element
client = client(url)
ssnns = ('ssn', 'http://namespaces/sessionid')
ssn = Element('SessionID', ns=ssnns).setText('123')
client.set_options(soapheaders=ssn)
result = client.service.addPerson(person)
千万不能尝试通过标题为XML“字符串”,如:
#!python
client = client(url)
ssn = '<ssn:SessionID>123</ssn:SessionID>'
client.set_options(soapheaders=ssn)
result = client.service.addPerson(person)
它不起作用,因为:
1.仅将[suds.sax.element.Element-class.html Elements]作为“自定义”标题处理。1. XML字符串将被转义为&lt; ssn:SessionID&gt; 123&lt; / ssn:SessionID&gt; 无论如何。
WS-Security的
UsernameToken
使用'明文'密码(无摘要)提供的ws-security :
#!python
from suds.wsse import *
security = Security()
token = UsernameToken('myusername', 'mypassword')
security.tokens.append(token)
client.set_options(wsse=security)
或者,如果需要'Nonce'和'Create'元素,可以按如下方式生成和设置它们:
#!python
from suds.wsse import *
security = Security()
token = UsernameToken('myusername', 'mypassword')
token.setnonce()
token.setcreated()
security.tokens.append(token)
client.set_options(wsse=security)
但是,如果您想手动设置'Nonce'和/或'Created',您可以执行以下操作:
#!python
from suds.wsse import *
security = Security()
token = UsernameToken('myusername', 'mypassword')
token.setnonce('MyNonceString...')
token.setcreated(datetime.now())
security.tokens.append(token)
client.set_options(wsse=security)
多文档“Docuemnt /文字”
在大多数情况下,使用document / literal SOAP绑定样式定义的服务将单个文档定义为消息有效内容。<message />只有(1)<part/>
引用<element/>
模式中的a。在这种情况下,suds通过将方法签名显示为文档的内容(节点)来呈现该方法的RPC视图。例如:
#!xml
<schema>
...
<xs:element name="Foo" type = "tns:Foo"/>
<xs:complexType name="Foo">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:complexType>
...
</schema>
<definitions>
...
<message name="FooMessage">
<part name="parameters" element="Foo">
</message>
...
</definitions>
Suds会将方法'foo'签名报告为:
foo(xs:string name, xs:int age,)
这为document / literal soap绑定样式提供了RPC感觉。
现在,如果wsdl定义:
#!xml
<schema>
...
<xs:element name="Foo" type = "tns:Foo"/>
<xs:element name="Bar" type = "xs:string"/>
<xs:complexType name="Foo">
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:int"/>
</xs:sequence>
</xs:complexType>
...
</schema>
<definitions>
...
<message name="FooMessage">
<part name="foo" element="Foo">
<part name="bar" element="Bar">
</message>
...
</definitions>
Suds将被强制报告方法'foo'签名为:
foo(Foo foo, xs:int bar)
该消息具有(2)部分,其定义消息有效载荷包含(2)文档。在这种情况下,肥皂水必须呈现/Document/
该方法的视图。
HTTP认证
基础
[ http://www.ietf.org/rfc/rfc2617.txt RFC-2617] 定义的HTTP身份验证可以按如下方式完成:
#!python
client = Client(url, username='elmer', password='fudd')
身份验证由[suds.transport.http-module.html transport.https]模块中定义的(默认)[suds.transport.https.HttpAuthenticated-class.html HttpAuthenticated]'Transport'类提供(http) 401)/ RFC中定义的响应模型。
'Transport'[suds.transport.http-module.html transport.http]模块,为不遵循质询/响应模型的服务器提供http身份验证。相反,它在所有 http请求上设置'Authentication:'http标头。此传输可以使用如下:
#!python
from suds.transport.http import HttpAuthenticated
t = HttpAuthenticated(username='elmer', password='fudd')
client = Client(url, transport=t)
要么:
#!python
from suds.transport.http import HttpAuthenticated
t = HttpAuthenticated()
client = Client(url, transport=t, username='elmer', password='fudd')
Windows(NTLM)
Suds包含基于urllib2的[suds.transport.https.WindowsHttpAuthenticated-class.html NTLM传输]。此实现要求“用户”安装[ http://code.google.com/p/python-ntlm/ python-ntlm]。它没有与'suds'打包在一起。
要使用它,只需执行以下操作:
#!python
from suds.transport.https import WindowsHttpAuthenticated
ntlm = WindowsHttpAuthenticated(username='xx', password='xx')
client = Client(url, transport=ntlm)
代理
suds默认[suds.transport.HttpTransport-class.html transport]使用处理代理urllib2.Request.set_proxy()
。可以使用设置传递代理选项Client.set_options
。代理选项必须包含字典,其中keys=protocols
和值是代理的主机名(或IP)和端口:
#!python
...
d = dict(http='host:80', https='host:443', ...)
client.set_options(proxy=d)
...
消息注入INJECTION'(诊断/测试)'
服务API提供消息/回复注入。
要注入要发送的soap消息或注入要处理的回复或错误,就好像soap服务器返回的那样,只需使用__inject
包含以下任一项的字典值指定关键字参数:
- 'msg'= <消息字符串>
- 'reply'= <reply string>
- 'fault'= <故障串>
在调用服务时。例如:
发送'原始'肥皂消息:
#!python
message = \
"""<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"""
print client.service.test(__inject={'msg':message})
注入测试响应:
#!python
reply = \
"""<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
...
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"""
print client.service.test(__inject={'reply':reply})
表现
Suds提供了一些URL缓存。默认情况下,缓存获取WSDL和导入XSD等http get(s)。缓存适用于URL,例如那些用于获取引用的WSDL和XSD架构但并不适用于服务方法调用,因为这是没有意义的。
默认的'cache'是[suds.cache.ObjectCache-class.html ObjectCache],有效期为(1)天。
此持续时间可以调整如下:
#!python
cache = client.options.cache
cache.setduration(days=10)
要么:
#!python
cache.setduration(seconds=90)
'持续时间'是我的(月,周,日,小时,秒)。
默认的“位置”(目录)是'/ tmp / suds'所以'Windows'用户需要将'location'设置为在Windows上有意义的东西。
缓存是[suds.options.Options-class.html选项],可以使用任何类型的[suds.cache.Cache-class.html Cache]对象进行设置,也可以通过将选项设置为“无”来禁用。因此,用户可以“插入”他们想要的任何类型的缓存:
#!python
from suds.cache import Cache
class MyCache(Cache)
...
client.set_options(cache=MyCache())
要禁用缓存:
#!python
client.set_options(cache=None)
修复损坏的模式
在许多情况下,在WSDL中定义的模式或导入的模式都被破坏。最常见的问题是无法导入遵循正确的导入规则。也就是说,在一个模式中引用在另一个模式中定义的命名对象而不导入它。[suds.xsd.doctor-module.html doctor]模块定义了一组用于“修补”损坏模式的类。
医生
[suds.xsd.doctor.Doctor-class.html Doctor]类为提供此服务的类提供接口。一旦定义,在创建客户端时,可以使用模式'doctor'指定'doctor'作为[suds.options.Options-class.html选项]。或者,你可以使用股票'医生'之一
- [suds.xsd.doctor.ImportDoctor-class.html ImportDoctor] - 用于修复“导入”问题。
例如:
#!python
imp = Import('http://schemas.xmlsoap.org/soap/encoding/')
imp.filter.add('http://some/namespace/A')
imp.filter.add('http://some/namespace/B')
doctor = ImportDoctor(imp)
client = Client(url, doctor=doctor)
在这个例子中,我们已经指定'doctor'应该检查具有'targetNamespace' 的模式,并确保导入模式。如果这些模式对这些名称空间没有<xs:import />,则会添加它。http://some/namespace/A orhttp://some/namespace/B
http://schemas.xmlsoap.org/soap/encoding/
对于'schemaLocation'未绑定到'namespace'的情况,可以创建[suds.xsd.doctor.Import-class.html Import],指定'location'如下:
#!python
imp = Import('http://www.w3.org/2001/XMLSchema', location='http://www.w3.org/2001/XMLSchema.xsd')
imp.filter.add('http://some/namespace/A')
imp.filter.add('http://some/namespace/B')
doctor = ImportDoctor(imp)
client = Client(url, doctor=doctor)
通常引用的模式(未导入)是SOAP部分5编码模式。现在可以修复如下:
#!python
imp = Import('http://schemas.xmlsoap.org/soap/encoding/')
imp.filter.add('http://some/namespace/A')
doctor = ImportDoctor(imp)
client = Client(url, doctor=doctor)
将模式位置(URL)绑定到命名空间
一些WSDL模式导入为:without 和expect处理器使用命名空间URI作为命名空间的模式位置。处理规范将导入的命名空间的解析保留为模式,以便在未指定时处理器(在本例中为suds)的决定。Suds总是在WSDL中查找模式,但除非:<importnamespace="http://schemas.xmlsoap.org/soap/encoding/"/>
schemaLocation=""
<import/>
@schemaLocation
-
指定了schemaLocation,或
-
使用以下语法指定静态绑定:
#!python from suds.xsd.sxbasic import Import ns = 'http://schemas.xmlsoap.org/soap/encoding/' location = 'http://schemas.xmlsoap.org/soap/encoding/' Import.bind(ns, location)
或者,简写(当位置与名称空间URI相同时):
#!python
Import.bind(ns)
注意
http://schemas.xmlsoap.org/soap/encoding/'
自动'绑定'
插件
它旨在成为一种通用的,更具扩展性的机制,供用户在运行时检查/修改suds。今天,有两种“一次性”方式可以做到这一点:
- bindings.Binding.replyfilter - 可以检查和修改回复文本。
- xsd.Doctor - 医生'选项'用于修补破坏的模式。
[toc-suds.plugin-module.html插件]模块提供了许多类,但用户实际上只需要关注一些:
- [suds.plugin.Plugin-class.html Plugin]类,它定义用户插件的接口
- 传递给插件的'Context'类。
插件根据soap客户端的“任务”分为(4)类:
初始化:
客户端初始化任务,即客户端已经消化了WSDL和关联的XSD。
文件载入:
文档加载任务。这是客户端加载WSDL和XSD文档的时候。
消息:
消息传递任务是客户端在进行方法(操作)调用时执行soap消息传递。
!InitPlugin
'!InitPlugin'目前有(1)钩子:
initialized():
在客户端初始化后调用。上下文包含'WSDL'对象。
!DocumentPlugin
'!DocumentPlugin'目前有(2)个钩子:
loaded():
在解析“WSDL”或“XSD”文档之前调用。上下文包含url和文档文本。
parsed():
解析'WSDL'或'XSD'文档后调用。上下文包含url和文档'root'。
!MessagePlugin
'!MessagePlugin'目前有(5)个钩子:
marshalled():
为插件提供在发送之前检查/修改信封“文档”的机会。
发送():
为插件提供在发送之前检查/修改消息“text”的机会。
收到():
为插件提供在SAX解析之前检查/修改收到的XML“文本”的机会。
parsed():
为插件提供了在解组之前检查/修改sax解析的DOM树以进行回复的机会。
unmarshalled():
为插件提供在返回给调用者之前检查/修改未编组的回复的机会。
一般用法:
#!python
from suds.plugin import *
class MyPlugin(DocumentPlugin):
...
plugin = MyPlugin()
client = Client(url, plugins=[plugin])
插件只需要覆盖那些感兴趣的方法(钩子) - 而不是全部。捕获并记录异常。
这是一个例子。假设我想在soap信封中向文档根元素添加一些属性。目前suds没有提供使用主API执行此操作的方法。使用类似于架构医生的插件,我们可以做到这一点。
假设我们的信封由肥皂水生成:
<soapenv:Envelope>
<soapenv:Body>
<ns0:foo>
<name>Elmer Fudd</name>
<age>55</age>
</ns0:foo>
</soapenv:Body>
</soapenv:Envelope>
但你需要的是:
<soapenv:Envelope>
<soapenv:Body>
<ns0:foo id="1234" version="2.0">
<name>Elmer Fudd</name>
<age>55</age>
</ns0:foo>
</soapenv:Body>
</soapenv:Envelope>
#!python
from suds.plugin import MessagePlugin
class MyPlugin(MessagePlugin):
def marshalled(self, context):
body = context.envelope.getChild('Body')
foo = body[0]
foo.set('id', '12345')
foo.set('version', '2.0')
client = Client(url, plugins=[MyPlugin()])
将来,Binding.replyfilter
“医生” 选项可能会被弃用。[suds.xsd.doctor.ImportDoctor-class.html ImportDoctor]已扩展为实现API。[suds.plugin.Plugin-class.htmlPlugin].onLoad()
在这样做时,我们可以将!ImportDoctor视为插件:
#!python
imp = Import('http://www.w3.org/2001/XMLSchema')
imp.filter.add('http://webservices.serviceU.com/')
d = ImportDoctor(imp)
client = Client(url, plugins=[d])
我们也可以Binding.replyfilter()
用插件替换我们的插件如下:
#!python
def myfilter(reply):
return reply[1:]
Binding.replyfilter = myfilter
# replace with:
class Filter(MessagePlugin):
def received(self, context):
reply = context.reply
context.reply = reply[1:]
client = Client(url, plugins=[Filter()])
技术(FYI)备注
- XML名称空间表示为元组(前缀,URI)。默认命名空间是
(None,None)
。 -
- suds.sax模块是由becuase elementtree和其他python XML包编写的:有一个非常不友好的DOM API或者
- (在elementtree的情况下)不要充分处理名称空间,特别是前缀。
-
- 限定引用是WSDL中引用的类型,例如
<tag type="tns:Person/>
- 其中限定引用是元组,其中命名空间是元组的第二部分。如果未提供前缀,则命名空间是定义片段的targetNamespace。这可确保所有查找和比较都是完全限定的。
('Person', ('tns','http://myservce/namespace'))
<tag type="Person/>
- 文章来源:https://suds-py3.readthedocs.io/en/latest/
- 限定引用是WSDL中引用的类型,例如
布施恩德可便相知重
微信扫一扫打赏
支付宝扫一扫打赏