简体   繁体   中英

Accessing response soap header using suds

I have a soap 1.1/1.2 web service I'm trying to access using suds .

Unfortunately the service puts authentication token in response soap header.

Is it possible to access the header somehow?

I know one can set a custom soap header in the request, but that's not what I'm looking for.

I've been using the (still maintained) suds-jurko branch, and ran into trouble because client.last_received() was removed early after it was forked. So I had to figure out an alternative way to access the headers.

Fortunately, you can use a message plugin to store the parsed document, and then later access the headers via the plugin. For added convenience, instead of working with raw values from the xml document, you can process the headers based on the service-method, to get a correctly typed/structured value.

from suds.plugin import MessagePlugin

class HeaderPlugin(MessagePlugin):
    def __init__(self):
        self.document = None

    def parsed(self, context):
        self.document = context.reply

    def get_headers(self, method):
        method = method.method
        binding = method.binding.output
        rtypes = binding.headpart_types(method, False)

        envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
        soapenv = self.document.getChild('Envelope', envns)
        soapheaders = soapenv.getChild('Header', envns)
        nodes = soapheaders.children
        if len(nodes):
            resolved = rtypes[0].resolve(nobuiltin=True)
            return binding.unmarshaller().process(nodes[0], resolved)
        return None

usage:

from suds.client import Client

hp = HeaderPlugin()
client = Client(wsdl, plugins=[hp])

response = client.service.LoremIpsum()
headers = hp.get_headers(client.service.LoremIpsum)

example output:

>>> headers
(AuthenticationResponseHeader){
   sessionKey = "a631cd00-c6be-416f-9bd3-dbcd322e0848"
   validUntil = 2030-01-01 01:01:01.123456+01:00
 }
>>> headers.validUntil
datetime.datetime(2030, 1, 1, 1, 1, 1, 123456, tzinfo=<suds.sax.date.FixedOffsetTimezone object at 0x7f7347856be0>)

You can do something like

print client.last_received().getChild("soap:Envelope").getChild("soap:Header")
.getChild("ResponseHeader").getChild("resultCode").getText()

The above reads a field resultCode in the soap header. You have to do this for each field. This was a back door left to read headers as much as i know.

For details look at soap headers with suds

The Towr's class plugin works well, but it has a problem when do you have more then one obj in Soapheader Response. His code get only the first object.

Here is the code to improvement the Towr's class:

class HeaderPlugin(MessagePlugin):
    def __init__(self):
        self.document = None

    def parsed(self, context):
        self.document = context.reply

    def get_headers(self, method):
        Result = {}
        method = method.method
        binding = method.binding.output
        SHeaderElem = binding.headpart_types(method, False)

        envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
        soapenv = self.document.getChild('Envelope', envns)
        soapheaders = soapenv.getChild('Header', envns)
        SHeaderNodes = soapheaders.children

        for Elem in SHeaderElem:
            for Node in SHeaderNodes:
                if(Node.name == Elem.name):
                    ElemRes = Elem.resolve(nobuiltin=True)
                    NodeRes = binding.unmarshaller().process(Node, ElemRes)
                    Result[Elem.name] = NodeRes
        return Result
    #

To understand better, see the example. If do you receive this Soap Response:

<soap-env:Envelope xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
    <soap-env:Header>
        <eb:MessageHeader eb:version="1.0" soap-env:mustUnderstand="1">
            <!-- -->
        </eb:MessageHeader>
        <wsse:Security>
            <!-- -->
        </wsse:Security>
    </soap-env:Header>
    <soap-env:Body>
        <!-- -->
    </soap-env:Body>
</soap-env:Envelope>

The function get_headers will return a dict like this:

SoapHeadersResp = {'MessageHeader':MessageHeaderObj, 'Security':SecurityObj}

To use this class just follow the same steps that Towr said, replacing his HeaderPlugin class with this one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM