Send a request with arrays in Node-soap (node.js)

2019-08-07 16:26发布

问题:

I am communicating to a web service using nodejs and node-soap. But i just can't seem to get the syntax right for passing the parameters to the service.

The documentation says i need to send an array with the field uuid and its value.

Here is the Php code i got as an example from the web service owner

$uuid = "xxxx";

    $param = array("uuid"=>new SoapVar($uuid,
    XSD_STRING,
    "string", "http://www.w3.org/2001/XMLSchema")
    )

and here is the code i am using in my node server

 function getSoapResponse()
{
    var soap = require('soap');
      var url = 'http://live.pagoagil.net/soapserver?wsdl';
      var auth = [{'uuid': 'XXXXXXXXX'}];

      soap.createClient(url, function(err, client) {
      client.ListaBancosPSE(auth, function(err, result) 
      {
          console.log(result);
          console.log(err);
      });
  });

With this i get bad xml error

var auth = [{'uuid': 'XXXXXXXXX'}];

or

var auth = [["uuid",key1],XSD_STRING,"string","http://www.w3.org/2001/XMLSchema"];

and with this i get the response "the user id is empty" (the uuid)

 var auth = {'uuid': 'XXXXXXXXX'};

Any suggestions?

回答1:

There is not much I can do for you but here are a few tips to get you started.

  1. Use client.describe() to see how the service expects the arguments.

The service you are trying to reach has the following structure:

{ App_SoapService: 
    { App_SoapPort: 
        { Autorizar: [Object],
          AutorizarAdvance: [Object],
          AutorizarIac: [Object],
          ListaBancosPSE: [Object],
          AutorizarPSE: [Object],
          AutorizarTuya: [Object],
          AutorizarBotonCredibanco: [Object],
          FinalizarPSE: [Object],
          FinalizarTuya: [Object],
          ConsultarReferencia: [Object] } } }

Taking a closer look to the specific method ListaBancosPSE it provides this info:

{input: { auth: 'soap-enc:Array' },
 output: { return: 'soap-enc:Array' }}

I tried with this:

var soap = require('soap');

function getSoapResponse(url, auth) {
    soap.createClient(url, function(err, client) {
        console.log(client.describe());
        console.log(client.describe().App_SoapService.App_SoapPort.ListaBancosPSE);

        client.ListaBancosPSE(auth, function(err, result) {
            console.log(JSON.stringify(result));
            console.log(err);
        });
    });
}
getSoapResponse('http://live.pagoagil.net/soapserver?wsdl', {'soap-enc:Array' : {'uuid': 'XXXXXXXXX'}});

The response is the same "Negada, Error nombre de usuario vacio, No se pudo autenticar en pagoagil.net.".

The next steps for you would be to determine which is the message the service is expecting.

Could be something like:

<tns:ListaBancosPSE><uuid>XXXXXXXXX</uuid></tns:ListaBancosPSE>

Or

<tns:ListaBancosPSE><soap-enc:Array><uuid>XXXXXXXXX</uuid></soap-enc:Array></tns:ListaBancosPSE>

Once you know that, you just have to add a console.log in the node-soap package you installed, so go to where you have your node_modules installed and open the file

node_modules/soap/lib/client.js

Add a console.log at line 187, right after the message has been set and

console.log("Message! ", message);

This will show the message, that should give you enough information to figure out the format of the arguments.



回答2:

Finally using the content in this answer and modifying the code in the soap-node module i was able to obtain the code i needed.

I needed something like this:

      <auth xsi:type="ns2:Map">
        <item>
          <key xsi:type="xsd:string">uuid</key>
          <value xsi:type="xsd:string">{XXXXXX}</value>
        </item>
      </auth>

so I used this for creating the parameters:

var arrayToSend= 
{auth :
    [  
        {   'attributes' : {'xsi:type':"ns2:Map"}, 
            'item':  
                [
                    {'key' :
                        {'attributes' : 
                            { 'xsi:type': 'xsd:string'},
                            $value: 'uuid'
                        }
                    },
                    {'value' :
                        {'attributes' : 
                            { 'xsi:type': 'xsd:string'},
                            $value: uuid
                        }
                    }
                ]
        }   

    ]
};

and sent it like this:

soap.createClient(url, myFunction);


    function myFunction(err, client) 
    {
      client.ListaBancosPSE(arrayToSend,function(err, result) 
      {
          console.log('\n' + result);
      });
    }

Then the tricky part was modyfing the wsd.js so it didn't add a extra tag everytime i used and array. I went to line 1584 and changed the if for this:

    if (Array.isArray(obj)) 
  {
      var arrayAttr = self.processAttributes(obj[0]),
          correctOuterNamespace = parentNamespace || ns; //using the parent namespace if given
      parts.push(['<', correctOuterNamespace, name, arrayAttr, xmlnsAttrib, '>'].join(''));
    for (var i = 0, item; item = obj[i]; i++) 
    {

      parts.push(self.objectToXML(item, name, namespace, xmlns, false, null, parameterTypeObject, ancXmlns));
    }
      parts.push(['</', correctOuterNamespace, name, '>'].join(''));
  } 

basically now it does not push the open and close tag in every iterarion but instead only before and after the whole cycle.

Also i needed to add the definitions for the xlmns of the message. Client.js:186

xml = "<soap:Envelope " +
    "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
    'xmlns:xsd="http://www.w3.org/2001/XMLSchema"' +
    'xmlns:ns2="http://xml.apache.org/xml-soap"' +
    "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +

Hopefully this could be of help for people using this library and being in this situation.