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

如何移除node-soap服务器SOAP响应中的命名空间前缀

解决node-soap返回响应中tns前缀移除问题

我用node-soap搭建的SOAP服务器当前返回如下响应:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://localhost:8080/soap/server">
<soap:Body>
<tns:pingResponse>
<tns:name>e3499cd86f59508466e8c6fcd37aabc8</tns:name>
</tns:pingResponse>
</soap:Body>
</soap:Envelope>

需要将Body内的标签移除tns命名空间前缀,得到如下格式的响应:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://localhost:8080/soap/server">
<soap:Body>
<pingResponse>
<name>e3499cd86f59508466e8c6fcd37aabc8</name>
</pingResponse>
</soap:Body>
</soap:Envelope>

尝试过两种方法均失败:

  • 移除WSDL中的xmlns:tns="http://localhost:8080/soap/server"后,前缀变为undefined:;
  • 移除<soap:binding>中的style="rpc"后,服务器返回错误:
<soap:Envelopexmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:tns="http://localhost:8080/soap/server">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>SOAP-ENV:Server</soap:Value>
<soap:Subcode>…</soap:Subcode>
</soap:Code>
<soap:Reason>
<soap:Text>TypeError: Cannot read properties of undefined (reading &apos;outputName&apos;)</soap:Text>
</soap:Reason>
</soap:Fault>
</soap:Body>
</soap:Envelope>

查遍node-soap的npm文档未找到相关解决方法,求可行方案。


当前使用的代码

WSDL

<wsdl:definitions
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://localhost:8080/soap/server"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    name="Cos_Service_Soap"
    targetNamespace="http://localhost:8080/soap/server"
>
    <wsdl:binding name="Cos_Service_SoapBinding" type="tns:Cos_Service_SoapPort">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="ping">
            <soap:operation soapAction="http://localhost:8080/soap/server#ping" />
            <wsdl:input>
                <soap:body use="literal" namespace="http://framework.zend.com" />
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal" namespace="http://framework.zend.com" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
<service name="Cos_Service_SoapService">
        <port name="Cos_Service_SoapPort" binding="Cos_Service_SoapBinding">
            <soap:address location="http://localhost:8080/soap/server" />
        </port>
    </service>
<message name="pingIn" />
    <message name="pingResponse">
        <part name="return" type="xsd:string" />
    </message>
    <message name="pingOut">
        <part name="return" type="xsd:boolean" />
        <part name="name" type="xsd:boolean" />
    </message>
</wsdl:definitions>

服务器启动函数

function startServer() {
    server.listen(port);
    server.on('error', onError); 
    server.on('listening', onListening);

    soap.listen(server, {
        path: '/soap/server',
        services: poService.service,
        xml: poService.xml,
    });
}

服务逻辑

var poService = {
  Cos_Service_SoapService: {
    Cos_Service_SoapPort: {   
          ping: function(args) {  
              console.log(args);            
              return {'name': args.token};       
          },           
      } 
   }
}; 

解决方案

方案1:调整WSDL结构为document-literal风格

rpc风格的SOAP响应默认会给元素添加目标命名空间前缀,改成document风格并完善WSDL定义可以解决问题。原WSDL缺少portType和types定义,这是移除style="rpc"报错的核心原因,修改后的WSDL如下:

<wsdl:definitions
    xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:tns="http://localhost:8080/soap/server"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    name="Cos_Service_Soap"
    targetNamespace="http://localhost:8080/soap/server"
>
    <!-- 新增portType,定义接口操作规范 -->
    <wsdl:portType name="Cos_Service_SoapPort">
        <wsdl:operation name="ping">
            <wsdl:input message="tns:pingIn"/>
            <wsdl:output message="tns:pingResponse"/>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="Cos_Service_SoapBinding" type="tns:Cos_Service_SoapPort">
        <!-- 修改为document风格 -->
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="ping">
            <soap:operation soapAction="http://localhost:8080/soap/server#ping" />
            <wsdl:input>
                <soap:body use="literal" namespace="http://localhost:8080/soap/server" />
            </wsdl:input>
            <wsdl:output>
                <!-- 输出body不指定namespace,避免生成前缀 -->
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <service name="Cos_Service_SoapService">
        <port name="Cos_Service_SoapPort" binding="tns:Cos_Service_SoapBinding">
            <soap:address location="http://localhost:8080/soap/server" />
        </port>
    </service>

    <!-- 完善输入消息定义,和服务逻辑参数对应 -->
    <message name="pingIn">
        <part name="token" type="xsd:string"/>
    </message>
    <!-- 响应消息关联自定义元素 -->
    <message name="pingResponse">
        <part name="pingResponse" element="tns:pingResponse"/>
    </message>

    <!-- 新增types定义,明确响应元素结构 -->
    <wsdl:types>
        <xsd:schema targetNamespace="http://localhost:8080/soap/server" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:element name="pingResponse">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="name" type="xsd:string"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
        </xsd:schema>
    </wsdl:types>
</wsdl:definitions>

方案2:使用响应拦截器直接修改XML

如果不想改动WSDL结构,可以利用node-soap的onResponse钩子,在响应发送前直接替换掉tns前缀:

修改服务器启动函数:

function startServer() {
    server.listen(port);
    server.on('error', onError); 
    server.on('listening', onListening);

    soap.listen(server, {
        path: '/soap/server',
        services: poService.Cos_Service_SoapService, // 修正原代码的services参数错误
        xml: poService.xml,
        // 添加响应拦截器
        onResponse: function(responseBody) {
            // 全局替换tns前缀标签
            return responseBody.replace(/<tns:([^>]+)>/g, '<$1>')
                               .replace(/<\/tns:([^>]+)>/g, '</$1>');
        }
    });
}

这个方法直接修改生成的XML字符串,简单高效,适合快速解决问题。如果需要保留某些tns前缀的元素,可以调整正则表达式的匹配规则。


内容的提问来源于stack exchange,提问作者fosfik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 13:14:54