使用构造的soap报文与Webservice通信

背景:项目使用了 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

# -- 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 = '' + 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

第二部分: soap_client.py


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

调用方式:
soap_client.call(目标IP, 目标端口, 方法名, 参数(Optional))

基于项目约定, webservice返回值一律为 json, 因此 call() 返回值为解析后的soap content,类型为 dict(python)

你可能感兴趣的:(使用构造的soap报文与Webservice通信)