我有一个我正在尝试使用suds访问的 soap 1.1/1.2 Web 服务。
不幸的是,该服务将身份验证令牌放在响应肥皂头中。
是否可以以某种方式访问标题?
我知道可以在请求中设置一个自定义的肥皂头,但这不是我想要的。
我一直在使用(仍然维护的)suds-jurko 分支,但遇到了麻烦,因为client.last_received()
它在分叉后很早就被删除了。所以我不得不想出一种访问标题的替代方法。
幸运的是,您可以使用消息插件来存储已解析的文档,然后通过插件访问标题。为了更加方便,您可以根据服务方法处理标头,而不是使用 xml 文档中的原始值,以获取正确键入/结构化的值。
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
用法:
from suds.client import Client
hp = HeaderPlugin()
client = Client(wsdl, plugins=[hp])
response = client.service.LoremIpsum()
headers = hp.get_headers(client.service.LoremIpsum)
示例输出:
>>> 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>)
你可以做类似的事情
print client.last_received().getChild("soap:Envelope").getChild("soap:Header")
.getChild("ResponseHeader").getChild("resultCode").getText()
上面读取了soap头中的一个字段resultCode。您必须为每个字段执行此操作。据我所知,这是阅读标题的后门。
有关详细信息,请查看带有泡沫的肥皂头
Towr 的类插件运行良好,但是当您在 Soapheader Response 中有多个 obj 时,它会出现问题。他的代码只得到第一个对象。
以下是改进 Towr 类的代码:
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
#
为了更好地理解,请参阅示例。如果您收到此 Soap 响应:
<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>
函数 get_headers 将返回一个像这样的字典:
SoapHeadersResp = {'MessageHeader':MessageHeaderObj, 'Security':SecurityObj}
要使用这个类,只需按照 Towr 所说的相同步骤,用这个替换他的 HeaderPlugin 类。