suds对接web service

webservice概念

1. Web service是一个平台独立的,松耦合的,自包含的、基于可编程的web的应用程序

2. 使用开放的XML标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序

SOAP :简单对象访问协议Simple Object Access Protocol,传输层,XML传输消息
WSDL:Web Server Description Language :Web Server描述语言(元数据),给客户端生成代理类的一个描述信息
UDDI :提供了一组基于标准的规范用于描述和发现服务,统一描述,发现和集成(UDDI-Universal Descript,Discovery,Integration),提供注册和查找服务 客户端在UDDI注册表(Registry)查找服务,取得服务的WSDL描述,通过SOAP调用服务。

简单的来说,webservice就是一个建立在Http之上数据结构为XML的协议,其中并不像平常访问API那样去访问web service接口,而是要访问相对应XML中的方法,以实现远程跨平台、跨语言的方法调用。通过XML形式说明服务在什么地方,以XML形式说明服务提供什么样的方法

一般来说内部开发会使用这种模式,但是也不缺乏对外公开的服务 如:手机号地区查询、天气预报查询 …

python对接web service

那么,如何使用python对接web service呢,我们可以使用suds!

pip3 install suds

为了方便测试客户端,可以使用这个网址中的web服务:http://www.webxml.com.cn/zh_cn/index.aspx

suds 的目标是基于 soap 的 Web 服务提供类似 RPC 的接口。这意味着在大多数情况下,用户不需要关心 WSDL 和引用模式的复杂性。无论指定哪种 soap 消息样式,服务方法的签名都保持不变。确实检查 WSDL 的用户会注意到,即使使用文档 soap 消息样式,每个方法的签名也类似于 RPC。

主要接口为 Client对象。它提供了配置库和定义的子命名空间的方法。创建 Client,它会处理 WSDL和引用的模式。从该信息中,它导出该信息的表示,该表示用于向用户提供服务描述和消息/回复处理

在调试中,可以使用logging来记录日志

import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)
  • suds.client: 在此模块上将日志记录级别设置为 DEBUG 以查看 soap 消息(输入和输出)和 http 标头。
  • suds.transport: 在此模块上将日志记录级别设置为 DEBUG 以查看有关 soap 消息(输入和输出)和 http 标头的更多详细信息。
  • suds.xsd.schema: 在此模块上将日志记录级别设置为 DEBUG 以查看模式的消化。
  • DEBUGsuds.wsdl: 在此模块上将日志记录级别设置为以查看消化 WSDL。

suds.Client为使用 Web 服务提供了统一的 API。该对象包含2个子命名空间:

service : service命名空间为消费的服务提供代理。该对象用于调用服务端点提供的操作(方法)。

factory : factory命名空间提供了一个工厂,可用于创建 WSDL 中定义的对象和类型的实例。

这两个为每个服务的 WSDL 的 url 创建一个客户端

from suds.client import Client
url = 'http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl'
client = Client(url)
print(client.__str__())

'''
Suds ( https://fedorahosted.org/suds/ )  version: 1.1.2

Service ( WeatherWS ) tns="http://WebXml.com.cn/"
   Prefixes (1)
      ns0 = "http://WebXml.com.cn/"
   Ports (2):
      (WeatherWSSoap)
         Methods (6):
            getRegionCountry()
            getRegionDataset()
            getRegionProvince()
            getSupportCityDataset(xs:string theRegionCode)
            getSupportCityString(xs:string theRegionCode)
            getWeather(xs:string theCityCode, xs:string theUserID)
         Types (91):
            ArrayOfString
            xs:ENTITIES
            xs:ENTITY
            xs:ID
            xs:IDREF
	'''

# 示例出现了 服务名为 WeatherWS 的6个方法以及91个Types, 例如 getRegionCountry()、getRegionDataset() ...

如果出现 suds.TypeNotFound: Type not found: ‘(schema, http://www.w3.org/2001/XMLSchema, )’ 这种错误,就进一步处理

from suds.client import Client
from suds.xsd.doctor import ImportDoctor, Import

url = 'http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?wsdl'
imp = Import(
    'http://www.w3.org/2001/XMLSchema',
    location='http://www.w3.org/2001/XMLSchema.xsd'
)
imp.filter.add('http://WebXml.com.cn/')
doctor = ImportDoctor(imp)
client = Client(url, doctor=doctor)

简单参数的调用

上面代码中返回WSDL中可调用的方法,现在就试着调用 getSupportCityDataset(xs:string theRegionCode)

可以看到方法中有参数并且为str类型,需要填入查询的地区代码。如果没有参数则直接调用

client = Client(url, doctor=doctor)
result = client.service.getSupportCityDataset("北京") # 也可以填写地区名称
print(result.diffgram.Region.City) # 获取到支持的城市数据级

'''
[(City){
   _id = "City1"
   _rowOrder = "0"
   CityID = "792"
   CityName = "北京"
 }, (City){
   _id = "City2"
   _rowOrder = "1"
   CityID = "785"
   CityName = "昌平"
 }, (City){
   _id = "City3"
   _rowOrder = "2"
   CityID = "826"
   CityName = "大兴"
 }...
 ]
'''

复杂参数

还有一些比较复杂的参数
比如 addPerson()方法接受一个类型为Person的参数,并具有一个签名:addPerson(Person person),其中参数类型后面跟着它的名称,相应的类型能在返回的Types中找到。在getWeather()的情况下,参数是xs:string类型的字符串 和 xs:int类型的整数。

因此,要创建一个Person对象作为参数传递,我们需要使用工厂子命名空间获得一个Person参数,如下所示:

person = client.factory.create('Person')
print(person)

'''
(Person)=
  {
    phone = []
    age = NONE
    name(Name) =
        {
            last = NONE
            first = NONE
        }
   }
 '''
# 对象是按照 WSDL 定义创建的。phone列表是空的,所以必须创建一个`Phone` 对象:
phone = client.factory.create('Phone')
phone.npa = 111
phone.nxx = 222
phone.number = 123123

# 创建一个`Name` 对象
name = client.factory.create('Name')
name.first = 'lu'
name.last = 'wei'

# 设置person属性
person.name = name
person.age = 25
person.phone = [phone]

# 或者
person.phone.append(phone)


# 调用方法
try:
   person_added = client.service.addPerson(person)
except WebFault as e:
  print e

或者可以使用Dict形式组装复杂参数

person = {}

phone = {
    'npa':111,
    'nxx':222,
    'number':123123,
}

name = {
    'first':'lu',
    'last':'wei'
}

person['name'] = name
person['age'] = 25
person['phone'] = [phone,]

try:
   person_added = client.service.addPerson(person)
except WebFault as e:
  print e

客户端可以配置为将web故障作为WebFault抛出,或者返回元组(<status>,<return value>),如下所示:

client = client(url, faults=False)
result = client.service.addPerson(person)
print(result)

suds的client选项说明

suds客户端有许多可以用来控制库的行为的功能。有些是通用选项,有些是运输选项。尽管选项对象是公开的,但首选和支持的设置/取消设置选项的方式是通过:

  • Client 构造函数
  • Client.set_options()
  • 构造函数 Transport

一般选项:

faults: 控制web故障行为

service: 控制多服务wsdl的默认服务名称

port:控制多端口服务的默认服务端口

location: 这将覆盖WSDL中定义的服务端口地址URL

transport: 控制插件web传输

cache: 提供与加载WSDL相关的文档和对象的缓存。肥皂信封从不缓存

cachingpolicy: 缓存策略,决定如何缓存数据。默认值为0。版本0.4+

​ 0=WSDL和XSD等XML文档

​ 1=WSDL对象图

soap标头:提供soap标头

wsse: 提供WS-Security对象

__inject:控制消息/回复消息的注入

doctor: 架构doctor指定用于修复损坏的架构的对象

xstq: XML架构类型限定标志指示xsi:type属性值应该由命名空间限定

prefixs: soap消息的元素应该使用XML前缀进行限定(在需要时),而不是xmlns=“”语法

retxml: 导致返回I{raw}soap信封而不是python对象图的标志

autoblend:确保WSDL中定义的架构相互导入的标志

nosend: 导致suds生成soap信封但不发送它的标志。相反,返回RequestContext Default:False

sortnamespaces: 使sud在存储命名空间时按字母顺序对其进行排序的标志。默认值:True

allowUnknownMessageParts: 与操作的WSDL架构定义相比,在接收web服务回复时检测到未知消息部分时引发异常。默认值:False

只有在使用默认传输时,才会使用传递给客户端构造函数的传输选项,如下所示:

proxy: 控制http代理设置。

timeout: URL连接超时(秒)默认值=90。每个方法调用也可以设置超时

headers: 提供额外的http标头

username: HTTP身份验证的用户名

password:HTTP身份验证的密码

通过交换零部件实现自定义行为

通过交换自定义,可以自定义suds的各种行为方式

初始化带有列表的可选阵列

在一些未发布的suds-jurko版本中,所有children元素都填充了空列表。这在suds社区中被修复为一种回归。这可能是所需的行为,因为它简化了构造复杂的请求。要获得先前的行为,请使用自定义生成器类,例如:

from suds.client import Client, Builder

class AlwaysInitializeBuilder(Builder):
    def skip_value(self, type):
        return False

client = Client(url)
client.factory.builder = AlwaysInitializeBuilder(client.factory.builder.resolver)

获取枚举变量

假设 wsdl 定义了以下枚举:

<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>

实力化枚举变量

resourceCategory = client.factory.create('resourceCategory')
client.service.getResourceByCategory(resourceCategory.PLATFORM)

工厂Factory

工厂用于创建由wsdl/schema定义的复杂对象

使用create()方法,因为它返回的对象已经具有正确的结构和模式类型信息。由于xsd支持嵌套类型定义,所以使用(.)点表示法的create()也是如此。例如,假设(Name)类型没有定义为顶级的“命名”类型,而是在(Person)类型中定义的。在这种情况下,创建(Name)对象必须通过其父对象的名称进行量化,并使用如下点表示法:

name = client.factory.create('Person.Name')

如果类型与wsdl(targetNamespace)在同一个命名空间中,则可以在没有任何命名空间限定的情况下引用它。如果不是,则该类型必须由命名空间前缀限定,例如:

name = client.factory.create('ns0:Person')

或者,名称可以由命名空间本身使用完整限定语法:

name = client.factory.create('{http://test.server.enterprise.rhq.org/}person')

当使用 (.) 点符号指定路径时,限定名称只能用于名称的第一部分

多个服务和多个端口的 WSDL

如果WSDL 定义了多个服务多个端口

Suds ( https://fedorahosted.org/suds/ )  version: 1.1.2

Service ( WeatherWS ) tns="http://WebXml.com.cn/"
   Prefixes (1)
      ns0 = "http://WebXml.com.cn/"
   Ports (2):
      (WeatherWSSoap)
         Methods (6):
            getRegionCountry()
            getRegionDataset()
            getRegionProvince()
            getSupportCityDataset(xs:string theRegionCode)
            getSupportCityString(xs:string theRegionCode)
            getWeather(xs:string theCityCode, xs:string theUserID)
         Types (91):
            ArrayOfString
            xs:ENTITIES
            xs:ENTITY
            xs:ID
            xs:IDREF
            xs:IDREFS
  		(WeatherWSSoap12)
         Methods (6):
            getRegionCountry()
            getRegionDataset()
            getRegionProvince()
            getSupportCityDataset(xs:string theRegionCode)
            getSupportCityString(xs:string theRegionCode)
            getWeather(xs:string theCityCode, xs:string theUserID)
         Types (91):
            ArrayOfString
            xs:ENTITIES
            xs:ENTITY
            xs:ID
            xs:IDREF
            xs:IDREFS
   Service ( WeatherWSTwo ) tns="http://WebXml.com.cn/"
   	 Prefixes (1)
      	ns0 = "http://WebXml2.com.cn/"
     Ports (2):
        (WeatherWSSoap)
           Methods (6):
              getRegionCountry()
              getRegionDataset()
              getRegionProvince()
              getSupportCityDataset(xs:string theRegionCode)
              getSupportCityString(xs:string theRegionCode)
              getWeather(xs:string theCityCode, xs:string theUserID)
           Types (91):
              ArrayOfString
              xs:ENTITIES
              xs:ENTITY
              xs:ID
              xs:IDREF
              xs:IDREFS
        (WeatherWSSoap12)
           Methods (6):
              getRegionCountry()
              getRegionDataset()
              getRegionProvince()
              getSupportCityDataset(xs:string theRegionCode)
              getSupportCityString(xs:string theRegionCode)
              getWeather(xs:string theCityCode, xs:string theUserID)
           Types (91):
              ArrayOfString
              xs:ENTITIES
              xs:ENTITY
              xs:ID
              xs:IDREF
              xs:IDREFS

想要指定服务或者指定端口如下所示

# 例子 client.service[service][port].getRegionCountry()

client.set_options(service='WeatherWSTwo', port='WeatherWSSoap12')
client.service.getRegionCountry()

# 或者 
client.service['WeatherWSTwo']['WeatherWSSoap12'].getRegionCountry()

# 或者按下标
client.service[1][0].getRegionCountry()

# 只选择service
client.service['WeatherWSTwo'].getRegionCountry()

# 按照service下标
client.service[1].getRegionCountry()

# 只按照port  
client.set_options(port='WeatherWSSoap')

请注意,如果WSDL定义了多个服务,则必须通过选项或使用下标语法来限定服务,以便指定端口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芦苇浮绿水

觉得还不错请博主喝杯饮料

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值