Node.js: como consumir serviço da web SOAP XML


99

Eu me pergunto qual é a melhor maneira de consumir serviço da web SOAP XML com node.js

Obrigado!


No caso de você usar node-soap e descobrir como usá-lo, você poderia me ajudar a criar um wsdl. Existe um gerador ou um bom tutorial de como escrever o wsdl. stackoverflow.com/questions/32480481/…
Andi Giga

Caso você precise de um exemplo de chamada de serviço .NET WCF, verifique minha resposta stackoverflow.com/a/63351804/1370029
Aliaksei Maniuk

Respostas:


83

Você não tem tantas opções.

Você provavelmente vai querer usar um dos seguintes:


3
Obrigado. tendo problemas com a instalação do node-soap porque a instalação do node-expat falhou = (
WHITECOLOR

Você precisará de cabeçalhos de desenvolvimento expat para criá-lo
Juicy Scripter

Descobri que o problema foi dito sobre os cabeçalhos, mas não sei onde devo obtê-lo, onde devo colocá-lo para compilar. Você poderia explicar, por favor?
WHITECOLOR

1
Provavelmente você pode obtê-los por meio de ferramentas de gerenciamento de pacotes para o seu sistema operacional. No Ubuntu, por exemplosudo apt-get install libexpat1-dev
Juicy Scripter

1
@RobertBroden, obrigado pela atualização. Da próxima vez, vá em frente e edite a resposta (ou sugira uma edição)!
Juicy Scripter

31

Acho que uma alternativa seria:

Sim, esta é uma abordagem bastante suja e de baixo nível, mas deve funcionar sem problemas


4
Infelizmente, este é o método mais confiável para interagir com SOAP com Node.js. Ainda estou para encontrar uma única biblioteca de sabão que faça solicitações de sabão de forma adequada no punhado de APIs que tenho que usar.
AlbertEngelB

1
100% sujo, mas me trouxe resultados)))
markkillah 01 de

o que todos vocês querem dizer com formar input xml` exatamente?
timaschew

sim, posso confirmar ainda, nenhuma das bibliotecas mencionadas acima funciona perfeitamente.
someUser de

Eu acho que "Form input xml" significa apenas fornecer um Content-Type de "text / xml"
SSH Este

22

Se node-soapnão funcionar para você, basta usarnode request módulo e converta o xml em json se necessário.

Minha solicitação não estava funcionando node-soape não há suporte para esse módulo além do suporte pago, que estava além dos meus recursos. Então eu fiz o seguinte:

  1. baixado SoapUI na minha máquina Linux.
  2. copiou o xml WSDL para um arquivo local
    curl http://192.168.0.28:10005/MainService/WindowsService?wsdl > wsdl_file.xml
  3. No SoapUI eu fui File > New Soap projecte carreguei meuwsdl_file.xml .
  4. No navegador, ampliei um dos serviços e cliquei com o botão direito na solicitação e cliquei em Show Request Editor.

De lá, eu poderia enviar uma solicitação e verificar se funcionou e também usar o RawouHTML dados para me ajudar a construir uma solicitação externa.

Raw da SoapUI para o meu pedido

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> 

Usei o acima para construir o seguinte 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);

obrigado @jtlindsey. Mas estou recebendo o método 405 não permitido como response.statusCode, response.statusMessage. Por acaso você sabe como consertar isso?
Sujoy

Houve um problema com meu URL. Eu estava usando a URL original em vez do terminal gerado pelo SOAPUI. Obrigado pelo código acima.
Sujoy

17

Consegui usar sabão, wsdl e Node.js. Você precisa instalar o sabão com npm install soap

Crie um servidor de nó chamado server.jsque definirá o serviço de sabão a ser consumido por um cliente remoto. Este serviço de sabonete calcula o Índice de Massa Corporal com base no peso (kg) e na 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);

Em seguida, crie um client.jsarquivo que consumirá o serviço soap definido por server.js. Este arquivo fornecerá argumentos para o serviço soap e chamará a url com portas de serviço e terminais 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);
      }
    });
  }
});

Seu arquivo wsdl é um protocolo baseado em xml para troca de dados que define como acessar um serviço da web remoto. Chame seu arquivo 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 que ajude


1
Muito obrigado. No entanto, tive que remover "res.send (resposta);" do cliente e "` "na última linha do arquivo do servidor.
Subhashi de

13

A maneira mais simples que descobri de apenas enviar XML bruto para um serviço SOAP usando Node.js é usar a implementação http do Node.js. Se parece com isso.

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();

Você teria definido a variável xml como o xml bruto na forma de uma string.

Mas se você deseja apenas interagir com um serviço SOAP via Node.js e fazer chamadas SOAP regulares, em vez de enviar xml bruto, use uma das bibliotecas Node.js. Eu gosto de sabão de nó .


1
#Halfstop, você poderia me dizer como fazer uma solicitação POST usando node-soap?
Abhishek saini

@Abhisheksaini o exemplo acima é uma postagem.
Meia parada de

@Halfstop Por favor, diga-me como incluir SOAPAction na solicitação.
Sohail,

12

Dependendo do número de terminais necessários, pode ser mais fácil fazer isso manualmente.

Eu tentei 10 bibliotecas "soap nodejs" e finalmente fiz manualmente.


Eu tentei o node-soap para acessar a rota wsdl, mas não funciona, continuo recebendo erros embora a mesma coisa funcione no php Você pode responder minha pergunta sobre como você fez isso stackoverflow.com/questions/39943122/…
Ammar Ajmal

8

Usei com sucesso o pacote "soap" ( https://www.npmjs.com/package/soap ) em mais de 10 WebApis de rastreamento (Tradetracker, Bbelboon, Affilinet, Webgains, ...).

Os problemas geralmente vêm do fato de que os programadores não investigam muito sobre o que a API remota precisa para se conectar ou autenticar.

Por exemplo, o PHP reenvia cookies de cabeçalhos HTTP automaticamente, mas ao usar o pacote 'node', ele deve ser definido explicitamente (por exemplo, pelo pacote 'soap-cookie') ...


usar o soap-cookie me ajudou a contornar um problema de autenticação que estava tendo no nó, muito obrigado!
nicolasdaudin


5

Usei o módulo de rede do nó para abrir um soquete para o serviço da 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 pedidos de sabonete

/* 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;
    }

Analisar a resposta do soap, usei o 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 ajude alguém


1
por que você faria isso em vez de usar o módulo http?
Will Munn de

0

Adicionando à solução de Kim .J : você pode adicionar preserveWhitespace=truepara evitar um erro de espaço em branco. Como isso:

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

0

Você também pode usar wsdlrdr. O EasySoap é basicamente reescrever o wsdlrdr com alguns métodos extras. Tome cuidado para que o easysoap não tenha o método getNamespace, que está disponível em wsdlrdr.


0

Para aqueles que são novos SOAPe querem uma explicação e um guia rápidos, eu recomendo fortemente este incrível artigo sobre mídia .

Você também pode usar o node-soap pacote , com este tutorial simples .


0

Se você precisa apenas de uma conversão única, https://www.apimatic.io/dashboard?modal=transform permite que você faça isso criando uma conta gratuita (sem afiliação, funcionou para mim).

Se você se transformar em Swagger 2.0, você pode fazer um js lib com

$ 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.