背景:项目使用了 gSoap 来自动生成 Webservice, 在尝试了诸多 python 类库之后( suds, pysoap等),均无法与server端正确通信
正因如此,开始尝试自己构造 soap 报文来与 Webservice 通信。
WebService 暴露的接口如下:
ControlDevice(xs:string deviceSerialNums, xs:string szCommandInfo, xs:string szCommandParam, xs:boolean bGroup, )
ExportConfigs(xs:string deviceSerialNum, xs:string softServiceName, xs:string configName, )
GetDeviceInfo(xs:string deviceSerialNums, xs:int nDeviceInfoType, xs:boolean bGroup, )
GetHSCConfig(xs:string deviceSerialNum, xs:string softServiceName, xs:string configName, )
GetSoftStatusInfo(xs:string deviceSerialNum, xs:string softServiceName, xs:string section, )
GetUpgradeProgress(xs:string deviceSerialNums, xs:string packagePath, xs:boolean bGroup, )
GetVersion()
ImportConfigs(xs:string deviceSerialNums, xs:string configContent, )
SetDeviceInfo(xs:string deviceSerialNum, xs:string newDeviceInfo, xs:boolean bGroup, )
SetDeviceNetInfo(xs:string deviceSerialNums, xs:string netInfo, xs:boolean bGroup, )
SetHSCConfigItem(xs:string deviceSerialNums, xs:string softServiceName, xs:string configName, xs:string newValues, )
UpgradeSoftware(xs:string deviceSerialNums, xs:string packagePath, xs:boolean bGroup, )
将整个client 工程分为两部分,第一部分用于构造 soap报文与整个post请求;第二部分使用 httplib 收发构造的请求与WebService的返回
第一部分: envelope.py
<code>
# -- coding: utf-8 --
# @Author: riposa
# @Date: 2016-07-15 11:12:15
# @Last Modified by: riposa
# @Last Modified time: 2016-07-15 17:58:46
'''
module for constructing soap request and resolve soap post
'''
import xml.etree.cElementTree as ET
import json
class SoapEnvelopeTree(object):
'''
Soap Envelope Tree parser
'''
def __init__(self, envString):
if not envString:
# construct new envelope xml tree
root = ET.Element('soapenv:Envelope')
root.set('xmlns:soapenv', 'http://schemas.xmlsoap.org/soap/envelope/')
ET.SubElement(root, 'soapenv:Body')
self.root = root
self.tree = ET.ElementTree(root)
else:
self.root = ET.fromstring(envString)
def set_sub_element(self, father, tag, text=None, attrib=None):
'''
add sub element to the specific father tag
'''
father_el = [ i for i in self.root.iter(father)][0]
if type(father_el) == None:
return ('error', 'can not find the node')
child = ET.SubElement(father_el, tag)
if text:
child.text = text
if attrib:
for i in attrib.keys():
child.set(i, attrib[i])
return 0
def get_post_content(self):
'''
get the soap post content(json) by resolving xml string
'''
try:
err_el = [ i for i in self.root.iter('SOAP-ENV:Fault')][0]
return ('error', err_el.find('faultstring').text)
except IndexError:
a = [j for j in self.root.iter('result')][0]
try:
return ('success', json.loads(a.text))
except ValueError:
return ('success', a.text)
def soap_request(url, method, param=None):
with open('header.conf') as head_file:
head = json.loads(head_file.read().replace(r'%url%', url))
env_tree = SoapEnvelopeTree(None)
env_tree.set_sub_element('soapenv:Body', 'ns1:%s' % method, None,
{"xmlns:ns1":"http://tempuri.org/vtns.xsd"})
if param:
for i in param.keys():
env_tree.set_sub_element('ns1:%s' % method, i, param[i], None)
data = '<?xml version="1.0" encoding="UTF-8"?>' + ET.tostring(env_tree.root, encoding='utf-8')
return (head, data)
def resolve_post(response):
env_tree_post = SoapEnvelopeTree(response)
(status, content) = env_tree_post.get_post_content()
return content
</code>
第二部分: soap_client.py
<code>
# -- coding: utf-8 --
# @Author: riposa
# @Date: 2016-07-15 14:48:29
# @Last Modified by: riposa
# @Last Modified time: 2016-07-15 17:02:12
'''module for send and recv soap message'''
import httplib
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from envelope import soap_request, resolve_post
def call(url, port, method, param=None):
(head, data) = soap_request(url, method, param)
http_client = httplib.HTTPConnection(url, port, timeout=5)
http_client.request('POST', '/', data, head)
try:
response = http_client.getresponse()
except httplib.BadStatusLine:
print 'illegal params cause no response'
result = resolve_post(response.read())
http_client.close()
return result
</code>
调用方式:
soap_client.call(目标IP, 目标端口, 方法名, 参数(Optional))
基于项目约定, webservice返回值一律为 json, 因此 call() 返回值为解析后的soap content,类型为 dict(python)
网友评论