Python Zeep调用外部SOAP API报错:消息无法处理
Hey, let's work through this since you already got it running in SoapUI—that's a great starting point! The error you're seeing points to a couple of likely mismatches between what Zeep is sending and what the service expects, based on your SoapUI request. Here's how to fix each one:
1. Set the Correct Service Endpoint
Zeep uses the endpoint defined in the WSDL by default, but you know from SoapUI that you need to use the /endpoint2 path instead. To override this in Zeep, just update the binding address after creating the client:
from zeep import Client from zeep.wsse.username import UsernameToken wsdl = 'https://asp.external.se/apps/api/service.svc?wsdl' token = UsernameToken('username', 'password') client = Client(wsdl=wsdl, wsse=token) # Replace with the exact endpoint you used in SoapUI client.service._binding_options['address'] = 'https://www.external.com/services/apiservice/endpoint2' # Now try your call again client.service.GetCompanies()
This is the most critical fix because the endpoint mismatch is explicitly called out in the error message ("mismatch between bindings").
2. Ensure the SOAPAction Header is Correct
The error also mentions an incorrect action value. SoapUI sends a specific SOAPAction header, and Zeep might be generating a different one based on the WSDL. You can manually specify the correct SOAPAction when calling the method:
# Pass the exact SOAPAction from your SoapUI request client.service.GetCompanies(_soapaction='www.external.com/services/apiservice/GetCompanies')
If all your methods need this same prefix, you can also check if the WSDL has incorrect SOAPAction values—but manually specifying it per call is quick to test.
3. Match the Security Header Requirements
Looking at your SoapUI request, the security header includes a Nonce and Created timestamp, but Zeep's default UsernameToken doesn't include these by default. Some services require these for security validation, so you'll need to extend the UsernameToken class to add them:
from zeep.wsse.username import UsernameToken from zeep.wsse.utils import create_timestamp, generate_nonce import xml.etree.ElementTree as etree class CustomUsernameToken(UsernameToken): def apply(self, envelope, headers): # Get the existing security header security = self.get_security_header(envelope) token = security.find('{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken') # Add Nonce element nonce = generate_nonce() nonce_elem = etree.SubElement( token, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Nonce' ) nonce_elem.set('EncodingType', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary') nonce_elem.text = nonce # Add Created timestamp created = create_timestamp() created_elem = etree.SubElement( token, '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Created' ) created_elem.text = created # Call the parent class method to add username/password return super().apply(envelope, headers) # Use the custom token instead of the default token = CustomUsernameToken('username', 'password') client = Client(wsdl=wsdl, wsse=token) client.service._binding_options['address'] = 'https://www.external.com/services/apiservice/endpoint2' client.service.GetCompanies(_soapaction='www.external.com/services/apiservice/GetCompanies')
Testing Order
I'd recommend testing these fixes one at a time:
- First update the endpoint and see if the error changes (or goes away)
- If you still get an action-related error, add the
_soapactionparameter - If security context errors persist, add the custom username token with Nonce/Created
That should cover all the mismatches between your working SoapUI request and Zeep's default behavior.
内容的提问来源于stack exchange,提问作者Majs

