You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WSDL编译生成SOAP请求执行报错,如何调整命名空间声明位置?

问题描述
  • 编译WSDL生成的SOAP请求结构合规,但执行时报错,请求内容如下:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
    <SOAP-ENV:Body>
        <tempuri2:BillInquiry xmlns:tempuri2="http://BillPayment_SOAP">
            <ESB_Header>
                <requestId>327823792977</requestId>
                <destSysOprName>ATM_BILL_INQ</destSysOprName>
                <tranTypeCode>       </tranTypeCode>
                <transmissionDateTime>20231005232051</transmissionDateTime>
                <RRN>327823792977</RRN>
                <deliveryChannelName>ATM</deliveryChannelName>
                <tenantId>ZyLA0LlEzox7Nb9yMUMGeQ==</tenantId>
            </ESB_Header>
            <billerID>ZONG0002</billerID>
            <feeFlag>N</feeFlag>
            <feeAmount>0</feeAmount>
            <stanID>792977</stanID>
            <RRN>327823792977</RRN>
            <consumerNo>11122233344</consumerNo>
            <channelId>117602</channelId>
        </tempuri2:BillInquiry>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  • 执行后返回的异常错误:
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><NS1:Fault xmlns:NS1="http://schemas.xmlsoap.org/soap/envelope/"><faultcode>-1</faultcode><faultstring>Exception Ouccured</faultstring></NS1:Fault></soapenv:Body></soapenv:Envelope>HTTP/1.1 500 Internal Server Error^M
Content-Type: text/xml;charset=utf-8^M
Server: IBM App Connect Enterprise^M
Date: Wed, 04 Oct 2023 11:45:25 GMT^M
Content-Length: 309^M
Connection: close^M
^M
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><NS1:Fault xmlns:NS1="http://schemas.xmlsoap.org/soap/envelope/"><faultcode>-1</faultcode><faultstring>Exception Ouccured</faultstring></NS1:Fault></soapenv:Body></soapenv:Envelope>
  • 将tempuri2命名空间声明移至<SOAP-ENV:Envelope>标签后,请求可正常执行,调整后的结构:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:tempuri2="http://BillPayment_SOAP">
    <SOAP-ENV:Body>
        <tempuri2:BillInquiry>
            <ESB_Header>
                <requestId>327823792977</requestId>
                <destSysOprName>ATM_BILL_INQ</destSysOprName>
                <tranTypeCode>       </tranTypeCode>
                <transmissionDateTime>20231005232051</transmissionDateTime>
                <RRN>327823792977</RRN>
                <deliveryChannelName>ATM</deliveryChannelName>
                <tenantId>ZyLA0LlEzox7Nb9yMUMGeQ==</tenantId>
            </ESB_Header>
            <billerID>ZONG0002</billerID>
            <feeFlag>N</feeFlag>
            <feeAmount>0</feeAmount>
            <stanID>792977</stanID>
            <RRN>327823792977</RRN>
            <consumerNo>11122233344</consumerNo>
            <channelId>117602</channelId>
        </tempuri2:BillInquiry>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
  • 尝试修改WSDL生成的代理文件引发错误,希望通过代码实现命名空间位置的调整。
解决方案

根据不同技术栈,可通过消息拦截/修改的方式调整命名空间位置:

Java(JAX-WS)

自定义SOAPHandler拦截出站消息,将命名空间从BillInquiry元素移至Envelope节点:

import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import java.util.Set;

public class NamespaceMoveHandler implements SOAPHandler<SOAPMessageContext> {
    private static final String TEMPURI_NS = "http://BillPayment_SOAP";
    private static final String TEMPURI_PREFIX = "tempuri2";

    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (isOutbound) {
            try {
                SOAPMessage message = context.getMessage();
                SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
                
                // 给Envelope添加命名空间声明
                envelope.addNamespaceDeclaration(TEMPURI_PREFIX, TEMPURI_NS);
                
                // 获取BillInquiry元素并移除自身的命名空间属性
                SOAPBody body = envelope.getBody();
                SOAPElement billInquiry = (SOAPElement) body.getChildElements(new QName(TEMPURI_NS, "BillInquiry")).next();
                billInquiry.removeAttribute("xmlns:" + TEMPURI_PREFIX);
                
                message.saveChanges();
            } catch (SOAPException e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    @Override
    public void close(MessageContext context) {}
}

注册Handler到客户端代理:

YourBillPaymentService service = new YourBillPaymentService();
BillPaymentPort port = service.getBillPaymentPort();
BindingProvider bindingProvider = (BindingProvider) port;
List<Handler> handlers = bindingProvider.getBinding().getHandlerChain();
handlers.add(new NamespaceMoveHandler());
bindingProvider.getBinding().setHandlerChain(handlers);

.NET(WCF)

自定义IClientMessageInspector修改出站请求消息:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Xml;

public class NamespaceAdjustInspector : IClientMessageInspector
{
    public void AfterReceiveReply(ref Message reply, object correlationState) {}

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var buffer = request.CreateBufferedCopy(int.MaxValue);
        var tempMsg = buffer.CreateMessage();
        XmlDocument doc = new XmlDocument();
        
        using (XmlReader reader = tempMsg.GetReaderAtBodyContents())
        {
            doc.Load(reader);
        }

        XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
        nsMgr.AddNamespace("soapenv", "http://www.w3.org/2003/05/soap-envelope");
        nsMgr.AddNamespace("tempuri2", "http://BillPayment_SOAP");
        
        // 给Envelope添加命名空间
        XmlElement envelope = doc.DocumentElement;
        envelope.SetAttribute("xmlns:tempuri2", "http://BillPayment_SOAP");
        
        // 移除BillInquiry元素上的命名空间属性
        XmlElement billInquiry = (XmlElement)doc.SelectSingleNode("//tempuri2:BillInquiry", nsMgr);
        billInquiry.RemoveAttribute("xmlns:tempuri2");
        
        // 重新构建请求消息
        using (XmlNodeReader newReader = new XmlNodeReader(doc))
        {
            Message modifiedMsg = Message.CreateMessage(tempMsg.Version, null, newReader);
            modifiedMsg.Headers.CopyHeadersFrom(request.Headers);
            modifiedMsg.Properties.CopyProperties(request.Properties);
            request = modifiedMsg;
        }
        
        buffer.Close();
        return null;
    }
}

// 注册Inspector的行为类
public class NamespaceAdjustBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) {}

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new NamespaceAdjustInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) {}

    public void Validate(ServiceEndpoint endpoint) {}
}

在客户端调用前添加行为:

var client = new BillPaymentServiceClient();
client.Endpoint.Behaviors.Add(new NamespaceAdjustBehavior());
var result = client.BillInquiry(yourRequestParams);

Python(Zeep)

自定义Zeep插件修改出站XML结构:

from zeep import Plugin
from lxml import etree

class NamespaceShiftPlugin(Plugin):
    def egress(self, envelope, http_headers, operation, binding_options):
        soap_env_ns = "http://www.w3.org/2003/05/soap-envelope"
        tempuri_ns = "http://BillPayment_SOAP"
        
        # 获取Envelope元素并添加命名空间
        envelope_elem = envelope.find(f"{{{soap_env_ns}}}Envelope")
        envelope_elem.set("xmlns:tempuri2", tempuri_ns)
        
        # 获取BillInquiry元素并移除自身的命名空间属性
        bill_inquiry_elem = envelope.find(f"{{{soap_env_ns}}}Body/{{{tempuri_ns}}}BillInquiry")
        if bill_inquiry_elem is not None and "xmlns:tempuri2" in bill_inquiry_elem.attrib:
            del bill_inquiry_elem.attrib["xmlns:tempuri2"]
        
        return envelope, http_headers

创建客户端时加载插件:

from zeep import Client

client = Client("your_wsdl_file.wsdl", plugins=[NamespaceShiftPlugin()])
client.service.BillInquiry(
    ESB_Header={...},
    billerID="ZONG0002",
    feeFlag="N",
    # 其他参数
)

内容的提问来源于stack exchange,提问作者Hadia-Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:17:07