杰瑞科技汇

Python如何添加SOAPHeader?

Of course! Working with SOAP headers in Python is a common requirement when interacting with web services, especially for authentication, routing, or other metadata. The most popular and robust library for this is zeep.

Python如何添加SOAPHeader?-图1
(图片来源网络,侵删)

Here's a comprehensive guide on how to work with SOAP headers in Python using the zeep library.

What is a SOAP Header?

A SOAP Header is an optional part of a SOAP message. It's used to convey information that is not directly related to the message payload itself. Common uses include:

  • Authentication: Passing username/password, API keys, or security tokens.
  • Routing: Information for message routers.
  • Session Management: Tracking sessions.
  • Transaction IDs: Correlating requests and responses.

The header is defined in the WSDL (Web Services Description Language) file of the service.


Prerequisites

First, you need to install the zeep library.

Python如何添加SOAPHeader?-图2
(图片来源网络,侵删)
pip install zeep

The Scenario

Let's imagine a simple web service that requires a custom header for authentication. The WSDL defines a header like this (conceptually):

<!-- In the WSDL <definitions> section -->
<wsdl:types>
  <xsd:schema>
    <xsd:element name="AuthHeader" type="tns:AuthHeader"/>
    <xsd:complexType name="AuthHeader">
      <xsd:sequence>
        <xsd:element name="Username" type="xsd:string"/>
        <xsd:element name="Password" type="xsd:string"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:schema>
</wsdl:types>
<!-- In the WSDL <binding> section, defining the header for a specific operation -->
<wsdl:operation name="GetUserInfo">
  <wsdl:input>
    <soap:header message="tns:GetUserInfoAuthHeader" part="AuthHeader" use="literal"/>
    <soap:body use="literal"/>
  </wsdl:input>
  ...
</wsdl:operation>

Our goal is to send a GetUserInfo request with the correct AuthHeader.


Method 1: Using a Python Dictionary (Simple & Common)

This is the most straightforward way. You create a Python dictionary that matches the structure of the header defined in the WSDL.

import zeep
# Replace with your actual WSDL URL
WSDL_URL = 'https://www.crcind.com/csp/samples/SOAP.Demo.cls?WSDL'
# 1. Create the Zeep client
client = zeep.Client(wsdl=WSDL_URL)
# 2. Define the header as a Python dictionary
# The keys must match the element names in the WSDL (case-sensitive)
# The top-level key is the name of the header element ('AuthHeader')
soap_header = {
    'AuthHeader': {
        'Username': 'myuser',
        'Password': 'mypassword'
    }
}
# 3. Create a new client instance that automatically includes the header
# This is a clean way to attach the header to all future operations.
client = zeep.Client(wsdl=WSDL_URL, soapheaders=soap_header)
# 4. Now, call the service method. The header will be sent automatically.
try:
    # The 'GetUserInfo' method takes an 'ID' parameter
    result = client.service.GetUserInfo(ID=12)
    print("Result with header:")
    print(result)
except Exception as e:
    print(f"An error occurred: {e}")

How it works:

Python如何添加SOAPHeader?-图3
(图片来源网络,侵删)
  • zeep inspects the WSDL and sees that the GetUserInfo operation expects a header named AuthHeader.
  • It sees that AuthHeader has two child elements, Username and Password.
  • It serializes your Python dictionary into the correct XML SOAP Header structure and adds it to the request.

Method 2: Using a zeep.xsd.Element (More Robust & Type-Safe)

For complex headers or when you want to be more explicit about the data types, you can use zeep.xsd.Element objects. This is often better for larger, more structured headers.

import zeep
from zeep import xsd
WSDL_URL = 'https://www.crcind.com/csp/samples/SOAP.Demo.cls?WSDL'
# 1. Create the Zeep client
client = zeep.Client(wsdl=WSDL_URL)
# 2. Define the header using zeep.xsd.Element
# This gives you more control over the XML structure and types.
# The first argument is the element name from the WSDL.
# The second argument is a dictionary of child elements.
auth_header_element = xsd.Element(
    'AuthHeader',
    xsd.ComplexType([
        xsd.Element('Username', xsd.String()),
        xsd.Element('Password', xsd.String())
    ])
)
# 3. Create an instance of the header element with data
# The keys here match the element names defined in the ComplexType.
soap_header_instance = auth_header_element(Username='myuser', Password='mypassword')
# 4. Create a new client with the header instance
client = zeep.Client(wsdl=WSDL_URL, soapheaders=soap_header_instance)
# 5. Call the service method
try:
    result = client.service.GetUserInfo(ID=12)
    print("\nResult with xsd.Element header:")
    print(result)
except Exception as e:
    print(f"An error occurred: {e}")

Why use this method?

  • Clarity: It makes the structure of the header very explicit.
  • Type Safety: You can define specific XSD types (like xsd.Integer(), xsd.Date()) to prevent type mismatches.
  • Reusability: You can define the header element once and reuse it in multiple client instances.

Handling Multiple Headers or Namespaces

Sometimes a service requires multiple headers or headers in a specific namespace. You can pass a list to the soapheaders parameter.

import zeep
from zeep import xsd
WSDL_URL = 'https://www.crcind.com/csp/samples/SOAP.Demo.cls?WSDL'
# Define the first header
auth_header = {
    'AuthHeader': {
        'Username': 'myuser',
        'Password': 'mypassword'
    }
}
# Define a second header, perhaps for routing or another purpose
# Let's assume the WSDL defines a 'RoutingHeader'
routing_header = {
    'RoutingHeader': {
        'Source': 'web-app',
        'Destination': 'internal-service'
    }
}
# Pass a list of headers to the client
client = zeep.Client(wsdl=WSDL_URL, soapheaders=[auth_header, routing_header])
try:
    result = client.service.GetUserInfo(ID=12)
    print("\nResult with multiple headers:")
    print(result)
except Exception as e:
    print(f"An error occurred: {e}")

Using Namespaces Explicitly

If a header is in a specific namespace (e.g., http://example.com/headers), you need to construct the header object more carefully. The dictionary method usually handles this if the WSDL is well-formed, but for complex cases, using xsd.Element is better as it allows you to specify namespaces.

# This is a more advanced example, assuming a namespaced header
ns = {'ns0': 'http://example.com/headers'}
# The dictionary key would need to be the qualified name
namespaced_header = {
    f'{{{ns["ns0"]}}}AuthHeader': {
        'Username': 'myuser',
        'Password': 'mypassword'
    }
}
# client = zeep.Client(wsdl=WSDL_URL, soapheaders=namespaced_header)

Inspecting the WSDL to Find Header Information

If you're not sure what the header should look like, use zeep to inspect the WSDL.

import zeep
WSDL_URL = 'https://www.crcind.com/csp/samples/SOAP.Demo.cls?WSDL'
client = zeep.Client(wsdl=WSDL_URL)
# Print all ports and operations
print(client.wsdl.dump())
# To find header information for a specific operation:
# 1. Get the binding object
binding = client.wsdl.bindings['DemoSoap']
# 2. Get the operation object
operation = binding.get('GetUserInfo')
# 3. Inspect the input message
print("\n--- GetUserInfo Input Message ---")
print(operation.signature('input'))
# Look for the 'header' part in the output to see its definition.

Summary: Which Method to Use?

Method When to Use Pros Cons
Dictionary For simple, flat headers. Quick and easy. Very simple, concise, readable. Less robust for complex or nested structures. Can be error-prone with typos.
zeep.xsd.Element For complex, nested, or strongly-typed headers. The recommended best practice. Type-safe, explicit structure, reusable, handles namespaces well. More verbose, requires a bit more setup.

For most use cases, starting with the dictionary method is perfectly fine. If you run into issues with complex headers or want to ensure your code is more robust, switch to the zeep.xsd.Element method.

分享:
扫描分享到社交APP
上一篇
下一篇