【问题标题】:node-soap adding namespace to envelopenode-soap 将命名空间添加到信封
【发布时间】:2021-01-11 23:48:24
【问题描述】:

我正在尝试使用此肥皂服务:http://testws.truckstop.com:8080/v13/Posting/LoadPosting.svc?singleWsdl 与 node-soap,但客户端正在破坏命名空间,我一直无法找到有效的解决方案。

我相信答案是要么给soap信封添加一个命名空间,要么覆盖soap信封。

使用Soap UI,请求应如下所示:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:v11="http://webservices.truckstop.com/v11" 
xmlns:web="http://schemas.datacontract.org/2004/07/WebServices">
   <soapenv:Header/>
   <soapenv:Body>
      <v11:GetLoads>
         <v11:listRequest>
            <web:IntegrationId>integrationId</web:IntegrationId>
            <web:Password>password</web:Password>
            <web:UserName>username</web:UserName>
         </v11:listRequest>
      </v11:GetLoads>
   </soapenv:Body>
</soapenv:Envelope>

但是,当我这样做时:

client = soap.createClient(url);
let query = {
        listRequest: {
            Password: password,
            UserName: username,
            IntegrationId: integrationId
        }
    };
let results = client.GetLoads(query);

客户端生成这个xml:

<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
        xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" 
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
        xmlns:tns="http://webservices.truckstop.com/v11" 
        xmlns:q1="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q2="http://schemas.datacontract.org/2004/07/WebServices.Objects" 
        xmlns:q3="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q4="http://schemas.datacontract.org/2004/07/WebServices.Objects" 
        xmlns:q5="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q6="http://schemas.datacontract.org/2004/07/WebServices.Objects" 
        xmlns:q7="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q8="http://schemas.datacontract.org/2004/07/WebServices.Objects" 
        xmlns:q9="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q10="http://schemas.datacontract.org/2004/07/WebServices.Objects" 
        xmlns:q11="http://schemas.datacontract.org/2004/07/WebServices.Posting" 
        xmlns:q12="http://schemas.datacontract.org/2004/07/WebServices.Objects">
        <soap:Body>
            <GetLoads xmlns="http://webservices.truckstop.com/v11">
                <listRequest>
                    <ns1:IntegrationId>integrationId</ns1:IntegrationId>
                    <ns1:Password>password</ns1:Password>
                    <ns1:UserName>usernam</ns1:UserName>
                </listRequest>
            </GetLoads>
        </soap:Body>
    </soap:Envelope>

这会失败,因为 IntegrationIdPasswordUserName 需要 http://schemas.datacontract.org/2004/07/WebServices,但信封中没有引用命名空间。

我已尝试更新客户端以将命名空间添加为suggested here

client.wsdl.definitions.xmlns.ns1 = "http://schemas.datacontract.org/2004/07/WebServices";
client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();

我可以在client.wsdl.xmlnInEnvelope 中看到命名空间,但它似乎并没有改变实际生成的 xml。

是否需要另一个步骤来刷新客户端以使用更新的信封?

我也试过overriding the root element as shown here

        var wsdlOptions = {
            //namespaceArrayElements: "xmlns:ns1=http://schemas.datacontract.org/2004/07/WebServices"

            "overrideRootElement": {
                "namespace": "xmlns:tns",
                "xmlnsAttributes": [{
                    "name": "xmlns:tns",
                    "value": "http://webservices.truckstop.com/v11"
                }, {
                    "name": "xmlns:ns1",
                    "value": "http://schemas.datacontract.org/2004/07/WebServices"
                }]
            }
        };
        this.loadPostClient = soap.createClient(this.tsConfig.loadPostUrl, wsdlOptions);

这会改变根主体元素:

<soap:Body>
    <xmlns:tns:GetLoads 
        xmlns:tns="http://webservices.truckstop.com/v11" 
        xmlns:ns1="http://schemas.datacontract.org/2004/07/WebServices">
        <listRequest>
            <ns1:IntegrationId>integrationId</ns1:IntegrationId>
            <ns1:Password>password</ns1:Password>
            <ns1:UserName>username</ns1:UserName>
        </listRequest>
    </xmlns:tns:GetLoads>
</soap:Body>

但是远程服务器不理解。

感谢您的阅读!

【问题讨论】:

    标签: soap node-soap


    【解决方案1】:

    This answer was correct all along

    由于自动完成和类似字段,它对我不起作用

    client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();
    

    应该是:

    client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap();
    

    我遗漏了 s 并设置了 xmlnInEnvelope 而不是 xmlnsInEvelope

    【讨论】:

      【解决方案2】:

      已经有几年了,但我遇到了类似的需要,需要向肥皂信封添加自定义属性,并想提供一个替代方案。

      在撰写本文时,_xmlnsMap() 是 WSDL 类上的 private method,因此您可以自行承担使用它的风险。我总是认为私有方法会受到开发人员的更改,而不会通知库使用者,所以我想找到另一种方法并证明它是可能的。

      TL;DR - 创建您自己的 WSDL 类实例并将其传递给您自己的 Client 类实例。

      • 使用open_wsdl 方法引入您的WSDL
      • 使用回调在串联字符串中构建您自己的自定义属性。
      • 将属性分配给公共xmlnsInEnvelope 属性。
      • 返回更新后的 WSDL 实例(我使用了 promise)。
      const fetchWSDL = new Promise<WSDL>((resolve, reject) => {
            // method that returns a WSDL instance from a url/file path
            open_wsdl(this.wsdl, (err: any, wsdl?: WSDL) => {
              // Build custom attributes
              if (wsdl && wsdl.definitions.xmlns) {
                const xmlns: { [key: string]: string } = {
                 [your namespaces]: 'values',
                };
      
                // turn your custom attributes map into a single concatenated string 
                let str = '';
                for (const alias in xmlns) {
                  const ns = xmlns[alias];
                  str += ' xmlns:' + alias + '="' + ns + '"';
                }
      
                // Leverage public attribute on WSDL instance to apply our custom attributes
                wsdl.xmlnsInEnvelope = str;
      
                resolve(wsdl);
              }
              reject(err);
            });
          });
      

      使用更新后的 WSDL 实例创建您自己的客户端。
      注意:createClient 方法只是用于创建 WSDL 实例并返回新客户端实例的便捷包装器。 p>

      const ModifiedWSDL = await fetchWSDL;
      
      // Create client with our modified WSDL instance
      this.client = new Client(ModifiedWSDL)
      
      // adjust your Client instance as needed
      

      比 OP 多一点代码,但希望更符合 node-soap 类型,如果您打算升级,使用起来更安全。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        • 2010-11-11
        • 2011-01-21
        • 2013-07-22
        相关资源
        最近更新 更多