A-A+

python suds zeep api

2019年01月16日 23:09 汪洋大海 暂无评论 共20582字 (阅读2,262 views次)

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/Bhttp://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。今天,有两种“一次性”方式可以做到这一点:

  1. bindings.Binding.replyfilter - 可以检查和修改回复文本。
  2. 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/

布施恩德可便相知重

微信扫一扫打赏

支付宝扫一扫打赏

×
标签:

给我留言