如何移除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 'outputName')</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
相关产品推荐
相关产品推荐

