Node.js: cómo consumir el servicio web XML SOAP


99

Me pregunto cuál es la mejor manera de consumir el servicio web SOAP XML con node.js

¡Gracias!


En caso de que use node-soap y descubra cómo usarlo, ¿podría ayudarme a crear un wsdl. ¿Existe un generador o un buen tutorial sobre cómo escribir el archivo wsdl. stackoverflow.com/questions/32480481/…
Andi Giga

En caso de que necesite un ejemplo para la llamada de servicio WCF de .NET, consulte mi respuesta stackoverflow.com/a/63351804/1370029
Aliaksei Maniuk

Respuestas:


83

No tienes tantas opciones.

Probablemente querrás usar uno de:


3
Gracias. teniendo problemas con la instalación de node-soap porque falla la instalación de node-expat = (
WHITECOLOR

Necesitará encabezados de desarrollo de expatriados para construirlo
Juicy Scripter

Encontré que el problema se ha dicho sobre los encabezados, pero no sé dónde debería conseguirlo, dónde debería ponerlo para compilarlo, ¿podría explicarme, por favor?
WHITECOLOR

1
Probablemente pueda obtenerlos a través de herramientas de administración de paquetes para su sistema operativo. En Ubuntu, por ejemplosudo apt-get install libexpat1-dev
Juicy Scripter

1
@RobertBroden, gracias por la actualización. La próxima vez, edite la respuesta (o sugiera una edición).
Juicy Scripter

31

Creo que una alternativa sería:

Sí, este es un enfoque bastante sucio y de bajo nivel, pero debería funcionar sin problemas.


4
Lamentablemente, este es el método más confiable para interactuar con SOAP con Node.js. Todavía tengo que encontrar una sola biblioteca de jabones que realice correctamente las solicitudes de jabón en el puñado de API que tengo que usar.
AlbertEngelB

1
100% sucio, pero me llevó a los resultados)))
markkillah

¿A qué se refieren exactamente con formar la entrada xml` exactamente?
timaschew

sí, aún puedo confirmar que ninguna de las bibliotecas mencionadas anteriormente funciona perfectamente.
someUser

Creo que "XML de entrada de formulario" significa simplemente dar un tipo de contenido de "texto / xml"
SSH Este

22

Si node-soapno funciona para usted, simplemente use el node requestmódulo y luego convierta el xml a json si es necesario.

Mi solicitud no funcionaba node-soapy no hay soporte para ese módulo más allá del soporte pagado, que estaba más allá de mis recursos. Entonces hice lo siguiente:

  1. descargué SoapUI en mi máquina Linux.
  2. copió el xml WSDL en un archivo local
    curl http://192.168.0.28:10005/MainService/WindowsService?wsdl > wsdl_file.xml
  3. En SoapUI fui File > New Soap projecty subí mi wsdl_file.xml.
  4. En el navegador expandí uno de los servicios, hice clic con el botón derecho en la solicitud y en Show Request Editor.

A partir de ahí me podría enviar una solicitud y asegurarse de que funcionaba y yo también podría utilizar el RawoHTML datos para ayudarme a crear una solicitud externa.

Raw de SoapUI para mi solicitud

POST http://192.168.0.28:10005/MainService/WindowsService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "http://Main.Service/AUserService/GetUsers"
Content-Length: 303
Host: 192.168.0.28:10005
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

XML de SoapUI

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:qtre="http://Main.Service">
   <soapenv:Header/>
   <soapenv:Body>
      <qtre:GetUsers>
         <qtre:sSearchText></qtre:sSearchText>
      </qtre:GetUsers>
   </soapenv:Body>
</soapenv:Envelope> 

Usé lo anterior para construir lo siguiente node request:

var request = require('request');
let xml =
`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:qtre="http://Main.Service">
   <soapenv:Header/>
   <soapenv:Body>
      <qtre:GetUsers>
         <qtre:sSearchText></qtre:sSearchText>
      </qtre:GetUsers>
   </soapenv:Body>
</soapenv:Envelope>`

var options = {
  url: 'http://192.168.0.28:10005/MainService/WindowsService?wsdl',
  method: 'POST',
  body: xml,
  headers: {
    'Content-Type':'text/xml;charset=utf-8',
    'Accept-Encoding': 'gzip,deflate',
    'Content-Length':xml.length,
    'SOAPAction':"http://Main.Service/AUserService/GetUsers"
  }
};

let callback = (error, response, body) => {
  if (!error && response.statusCode == 200) {
    console.log('Raw result', body);
    var xml2js = require('xml2js');
    var parser = new xml2js.Parser({explicitArray: false, trim: true});
    parser.parseString(body, (err, result) => {
      console.log('JSON result', result);
    });
  };
  console.log('E', response.statusCode, response.statusMessage);  
};
request(options, callback);

gracias @jtlindsey. Pero obtengo el método 405 no permitido como response.statusCode, response.statusMessage. Por casualidad, ¿sabe cómo solucionar este problema?
Sujoy

Hubo un problema con mi URL. Estaba usando la URL original en lugar del punto final generado por SOAPUI. Gracias por el código anterior.
Sujoy

17

Me las arreglé para usar soap, wsdl y Node.js Necesitas instalar soap con npm install soap

Cree un servidor de nodo llamado server.jsque definirá el servicio de jabón para ser consumido por un cliente remoto. Este servicio de jabón calcula el índice de masa corporal en función del peso (kg) y la altura (m).

const soap = require('soap');
const express = require('express');
const app = express();
/**
 * this is remote service defined in this file, that can be accessed by clients, who will supply args
 * response is returned to the calling client
 * our service calculates bmi by dividing weight in kilograms by square of height in metres
 */
const service = {
  BMI_Service: {
    BMI_Port: {
      calculateBMI(args) {
        //console.log(Date().getFullYear())
        const year = new Date().getFullYear();
        const n = args.weight / (args.height * args.height);
        console.log(n);
        return { bmi: n };
      }
    }
  }
};
// xml data is extracted from wsdl file created
const xml = require('fs').readFileSync('./bmicalculator.wsdl', 'utf8');
//create an express server and pass it to a soap server
const server = app.listen(3030, function() {
  const host = '127.0.0.1';
  const port = server.address().port;
});
soap.listen(server, '/bmicalculator', service, xml);

A continuación, cree un client.jsarchivo que consumirá el servicio de jabón definido por server.js. Este archivo proporcionará argumentos para el servicio SOAP y llamará a la URL con los puertos de servicio y los puntos finales de SOAP.

const express = require('express');
const soap = require('soap');
const url = 'http://localhost:3030/bmicalculator?wsdl';
const args = { weight: 65.7, height: 1.63 };
soap.createClient(url, function(err, client) {
  if (err) console.error(err);
  else {
    client.calculateBMI(args, function(err, response) {
      if (err) console.error(err);
      else {
        console.log(response);
        res.send(response);
      }
    });
  }
});

Su archivo wsdl es un protocolo basado en xml para el intercambio de datos que define cómo acceder a un servicio web remoto. Llame a su archivo wsdlbmicalculator.wsdl

<definitions name="HelloService" targetNamespace="http://www.examples.com/wsdl/HelloService.wsdl" 
  xmlns="http://schemas.xmlsoap.org/wsdl/" 
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
  xmlns:tns="http://www.examples.com/wsdl/HelloService.wsdl" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <message name="getBMIRequest">
    <part name="weight" type="xsd:float"/>
    <part name="height" type="xsd:float"/>
  </message>

  <message name="getBMIResponse">
    <part name="bmi" type="xsd:float"/>
  </message>

  <portType name="Hello_PortType">
    <operation name="calculateBMI">
      <input message="tns:getBMIRequest"/>
      <output message="tns:getBMIResponse"/>
    </operation>
  </portType>

  <binding name="Hello_Binding" type="tns:Hello_PortType">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <operation name="calculateBMI">
      <soap:operation soapAction="calculateBMI"/>
      <input>
        <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:examples:helloservice" use="encoded"/>
      </input>
      <output>
        <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:examples:helloservice" use="encoded"/>
      </output>
    </operation>
  </binding>

  <service name="BMI_Service">
    <documentation>WSDL File for HelloService</documentation>
    <port binding="tns:Hello_Binding" name="BMI_Port">
      <soap:address location="http://localhost:3030/bmicalculator/" />
    </port>
  </service>
</definitions>

Espero eso ayude


1
Muchas gracias. Sin embargo, tuve que eliminar "res.send (respuesta);" desde el cliente y "` "en la última línea del archivo del servidor.
Subhashi

13

La forma más sencilla que encontré para enviar XML sin formato a un servicio SOAP usando Node.js es usar la implementación http de Node.js. Se parece a esto.

var http = require('http');
var http_options = {
  hostname: 'localhost',
  port: 80,
  path: '/LocationOfSOAPServer/',
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': xml.length
  }
}

var req = http.request(http_options, (res) => {
  console.log(`STATUS: ${res.statusCode}`);
  console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
  res.setEncoding('utf8');
  res.on('data', (chunk) => {
    console.log(`BODY: ${chunk}`);
  });

  res.on('end', () => {
    console.log('No more data in response.')
  })
});

req.on('error', (e) => {
  console.log(`problem with request: ${e.message}`);
});

// write data to request body
req.write(xml); // xml would have been set somewhere to a complete xml document in the form of a string
req.end();

Habría definido la variable xml como xml sin formato en forma de cadena.

Pero si solo desea interactuar con un servicio SOAP a través de Node.js y realizar llamadas SOAP regulares, en lugar de enviar xml sin formato, use una de las bibliotecas de Node.js. Me gusta el jabón de nodos .


1
#Halfstop, ¿podría decirme cómo hacer una solicitud POST usando node-soap?
Abhishek saini

@Abhisheksaini el ejemplo anterior es una publicación.
Halfstop

@Halfstop Por favor, dígame cómo incluir SOAPAction en la solicitud.
Sohail

12

Dependiendo de la cantidad de puntos finales que necesite, puede ser más fácil hacerlo manualmente.

He probado 10 bibliotecas "soap nodejs" y finalmente lo hago manualmente.


Probé node-soap para acceder a la ruta wsdl pero no funciona, sigo recibiendo errores aunque lo mismo funciona en php ¿Pueden responder mi pregunta sobre cómo lo hicieron? Stackoverflow.com/questions/39943122/…
Ammar Ajmal

8

Utilicé con éxito el paquete "soap" ( https://www.npmjs.com/package/soap ) en más de 10 WebApis de seguimiento (Tradetracker, Bbelboon, Affilinet, Webgains, ...).

Los problemas generalmente provienen del hecho de que los programadores no investigan mucho sobre lo que necesita la API remota para conectarse o autenticarse.

Por ejemplo, PHP reenvía las cookies desde los encabezados HTTP automáticamente, pero cuando se usa el paquete 'nodo', debe configurarse explícitamente (por ejemplo, mediante el paquete 'soap-cookie') ...


el uso de soap-cookie me ayudó a evitar un problema de autenticación que estaba teniendo en el nodo, ¡muchas gracias!
nicolasdaudin


5

Usé el módulo de red de nodos para abrir un socket al servicio web.

/* on Login request */
socket.on('login', function(credentials /* {username} {password} */){   
    if( !_this.netConnected ){
        _this.net.connect(8081, '127.0.0.1', function() {
            logger.gps('('+socket.id + ') '+credentials.username+' connected to: 127.0.0.1:8081');
            _this.netConnected = true;
            _this.username = credentials.username;
            _this.password = credentials.password;
            _this.m_RequestId = 1;
            /* make SOAP Login request */
            soapGps('', _this, 'login', credentials.username);              
        });         
    } else {
        /* make SOAP Login request */
        _this.m_RequestId = _this.m_RequestId +1;
        soapGps('', _this, 'login', credentials.username);          
    }
});

Enviar solicitudes de jabón

/* SOAP request func */
module.exports = function soapGps(xmlResponse, client, header, data) {
    /* send Login request */
    if(header == 'login'){
        var SOAP_Headers =  "POST /soap/gps/login HTTP/1.1\r\nHost: soap.example.com\r\nUser-Agent: SOAP-client/SecurityCenter3.0\r\n" +
                            "Content-Type: application/soap+xml; charset=\"utf-8\"";        
        var SOAP_Envelope=  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
                            "<env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:SOAP-ENC=\"http://www.w3.org/2003/05/soap-encoding\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:n=\"http://www.example.com\"><env:Header><n:Request>" +
                            "Login" +
                            "</n:Request></env:Header><env:Body>" +
                            "<n:RequestLogin xmlns:n=\"http://www.example.com.com/gps/soap\">" +
                            "<n:Name>"+data+"</n:Name>" +
                            "<n:OrgID>0</n:OrgID>" +                                        
                            "<n:LoginEntityType>admin</n:LoginEntityType>" +
                            "<n:AuthType>simple</n:AuthType>" +
                            "</n:RequestLogin></env:Body></env:Envelope>";

        client.net.write(SOAP_Headers + "\r\nContent-Length:" + SOAP_Envelope.length.toString() + "\r\n\r\n");
        client.net.write(SOAP_Envelope);
        return;
    }

Analizar la respuesta de jabón, utilicé el módulo - xml2js

var parser = new xml2js.Parser({
    normalize: true,
    trim: true,
    explicitArray: false
});
//client.net.setEncoding('utf8');

client.net.on('data', function(response) {
    parser.parseString(response);
});

parser.addListener('end', function( xmlResponse ) {
    var response = xmlResponse['env:Envelope']['env:Header']['n:Response']._;
    /* handle Login response */
    if (response == 'Login'){
        /* make SOAP LoginContinue request */
        soapGps(xmlResponse, client, '');
    }
    /* handle LoginContinue response */
    if (response == 'LoginContinue') {
        if(xmlResponse['env:Envelope']['env:Body']['n:ResponseLoginContinue']['n:ErrCode'] == "ok") {           
            var nTimeMsecServer = xmlResponse['env:Envelope']['env:Body']['n:ResponseLoginContinue']['n:CurrentTime'];
            var nTimeMsecOur = new Date().getTime();
        } else {
            /* Unsuccessful login */
            io.to(client.id).emit('Error', "invalid login");
            client.net.destroy();
        }
    }
});

Espero que ayude a alguien


1
¿Por qué harías esto en lugar de usar el módulo http?
Will Munn

0

Agregando a la solución de Kim .J : puede agregar preserveWhitespace=truepara evitar un error de espacio en blanco. Me gusta esto:

soap.CreateClient(url,preserveWhitespace=true,function(...){

0

También puede utilizar wsdlrdr. EasySoap es básicamente una reescritura de wsdlrdr con algunos métodos adicionales. Tenga cuidado de que easysoap no tenga el método getNamespace que está disponible en wsdlrdr.


0

Para aquellos que son nuevos SOAPy desean una explicación y una guía rápidas, les recomiendo este increíble artículo mediano. .

También puede utilizar el node-soap paquete , con este sencillo tutorial .


0

Si solo necesita una conversión única, https://www.apimatic.io/dashboard?modal=transform le permite hacer esto creando una cuenta gratuita (sin afiliación, simplemente funcionó para mí).

Si se transforma en Swagger 2.0, puede hacer una lib js con

$ wget https://repo1.maven.org/maven2/io/swagger/codegen/v3/swagger-codegen-cli/3.0.20/swagger-codegen-cli-3.0.20.jar \
  -O swagger-codegen-cli.jar
$ java -jar swagger-codegen-cli.jar generate \
  -l javascript -i orig.wsdl-Swagger20.json -o ./fromswagger
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.