如何将未在WSDL文件中定义的SOAP头传入Python SUDS

15 投票
1 回答
20175 浏览
提问于 2025-04-15 20:34

我在我的网络上有一台摄像头,我想用suds来连接它,但suds没有发送所有需要的信息。我需要添加一些在WSDL文件中没有定义的额外SOAP头,这样摄像头才能理解这个消息。所有的头信息都包含在一个SOAP信封里,而suds的命令应该放在消息的主体部分。

我查看了suds的官方网站,上面说可以这样传递头信息:(这个方法是把元素作为头信息传递,但我有一个信封,所以我不太确定该怎么输入)

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 version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP
ENC="http://www.w3.org/2003/05/soap-encoding"
<wsa:MessageID SOAP-ENV:mustUnderstand="true">urn:uuid:43268c01-f09c6</wsa:MessageID>
 <SOAP-ENV:Header>

使用这个或类似的例子,有人知道我该如何将一个有效的SOAP消息传递给目标服务吗?

谢谢

1 个回答

22

我已经弄明白了如何在suds中添加新的头信息和命名空间。就像上面说的,你需要创建一个元素,然后把它作为soap头传进去,方法如下:

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)

如果你想添加一个命名空间,我发现加一个前缀就可以了。所以在你创建元素的时候,添加 addPrefix。我不确定这是不是官方推荐的做法,但它确实有效。

ssn = Element('SessionID', ns=ssnns).setText('123').addPrefix(p='SOAP-ENC', u='http://www.w3.org/2003/05/soap-encoding')

p = 'SOAP-ENC' 可以是任何前缀,比如 eg. wsa,而 u = http://address 是命名空间的地址。

一个完整的可以运行的脚本可能是:

#!/usr/local/bin/python2.6

import suds
#import logging
from suds.client import Client
from suds.sax.element import Element
from suds.sax.attribute import Attribute
from suds.xsd.sxbasic import Import

def absoluteMove():

    # connects to WSDL file and stores location in variable 'client'
    client = Client('http://10.10.10.10/p.wsdl')
    client.options.location = 'http://10.10.10.10:32963'

    # Create the header
    wsans = ('wsa', 'http://schemas.xmlsoap.org/ws/2004/08/addressing')
    mustAttribute = Attribute('SOAP-ENV:mustUnderstand', 'true')
    n1s = ('SOAP-ENC', 'http://www.w3.org/2003/05/soap-encoding')
    msgId = Element('Element').addPrefix(p='SOAP-ENC', u='http://www.w3.org/2003/05/soap-encoding')

    msgId2 = Element('Address', ns=wsans).setText('http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous')
    msgId1 = Element('ReplyTo', ns=wsans).insert(msgId2)
    msgId1.append(mustAttribute)

    msgId3 = Element('To', ns=wsans).setText('http://10.10.10.10:32954')
    msgId3.append(mustAttribute)

    client.set_options(soapheaders=[msgId, msgId1, msgId3, msgId2])

    # Create 'token' object to pass as an argument using the 'factory' namespace
    token = client.factory.create('ns4:ReferenceToken')

    # Create 'dest' object to pass as an argument and values passed to this object
    dest = client.factory.create('ns4:PTZVector')
    dest.PanTilt._x=1
    dest.PanTilt._y=4.9
    dest.Zoom._x=1


    # Create 'speed' object to pass as an argument and values passed to this object
    speed = client.factory.create('ns4:PTZSpeed')
    speed.PanTilt._x=0
    speed.PanTilt._y=0
    speed.Zoom._x=1

    # 'AbsoluteMove' method invoked passing in the new values entered in the above objects

    try:
        result = client.service.AbsoluteMove(token, dest, speed)
        print "absoluteMove result ", result
        return result
    except suds.WebFault, e:
        print "suds.WebFaults caught: "
        print e

if __name__ == '__main__': result = absoluteMove()

这个脚本可以移动相机。如果你想更改soap信封的类型,可以查看 我的下一个问题

你可以在这个脚本中添加日志记录,这样你就可以检查你发送了什么xml命令,这很方便:

import logging
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)

如果位置不在wsdl文件中,可以把位置作为选项放入脚本中。

撰写回答