IT story

Node.js : SOAP XML 웹 서비스를 사용하는 방법

hot-time 2020. 9. 13. 11:51
반응형

Node.js : SOAP XML 웹 서비스를 사용하는 방법


node.js로 SOAP XML 웹 서비스를 사용하는 가장 좋은 방법이 무엇인지 궁금합니다.

감사!


그다지 많은 옵션이 없습니다.

다음 중 하나를 사용하고 싶을 것입니다.


나는 대안이 될 것이라고 생각합니다.

  • SoapUI ( http://www.soapui.org ) 와 같은 도구를 사용하여 입력 및 출력 xml 메시지를 기록합니다.
  • 노드 요청 ( https://github.com/mikeal/request )을 사용 하여 웹 서비스에 요청을 보낼 (POST) 입력 xml 메시지를 형성합니다 (ejs ( http://embeddedjs.com 과 같은 표준 자바 스크립트 템플릿 메커니즘) / ) 또는 콧수염 ( https://github.com/janl/mustache.js )이 여기에서 도움이 될 수 있습니다) 그리고 마지막으로
  • XML 파서를 사용하여 응답 데이터를 JavaScript 개체로 deserialize

예, 이것은 다소 더럽고 낮은 수준의 접근 방식이지만 문제없이 작동합니다.


경우 node-soap당신을 위해 일을하지 않습니다, 단지 사용하는 node request모듈을하고 필요한 경우 다음 JSON으로 XML을 변환합니다.

내 요청이 작동 node-soap하지 않았고 내 리소스를 초과하는 유료 지원 외에 해당 모듈에 대한 지원이 없습니다. 그래서 다음을 수행했습니다.

  1. 내 Linux 컴퓨터에 SoapUI다운로드 했습니다 .
  2. WSDL xml을 로컬 파일에 복사했습니다.
    curl http://192.168.0.28:10005/MainService/WindowsService?wsdl > wsdl_file.xml
  3. SoapUI에서 나는에 가서 File > New Soap project내 업로드 wsdl_file.xml.
  4. 네비게이터에서 서비스 중 하나를 확장하고 요청을 마우스 오른쪽 버튼으로 클릭하고을 클릭했습니다 Show Request Editor.

거기에서 요청을 보내고 제대로 작동하는지 확인할 수 있으며 Raw또는 HTML데이터를 사용하여 외부 요청을 작성할 수도 있습니다 .

내 요청에 대한 SoapUI의 원시

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)

SoapUI의 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> 

위를 사용하여 다음을 빌드했습니다 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);

Node.js를 사용하여 SOAP 서비스에 원시 XML을 보내는 가장 간단한 방법은 Node.js http 구현을 사용하는 것입니다. 이렇게 생겼어요.

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

xml 변수를 문자열 형식의 원시 xml로 정의했을 것입니다.

그러나 원시 xml을 보내는 대신 Node.js를 통해 SOAP 서비스와 상호 작용하고 일반 SOAP 호출을 수행하려는 경우 Node.js 라이브러리 중 하나를 사용하십시오. 나는 node-soap을 좋아 합니다 .


나는 soap, wsdl 및 Node.js를 사용했습니다. npm install soap

server.js원격 클라이언트가 사용할 SOAP 서비스를 정의하는 라는 노드 서버를 작성하십시오 . 이 비누 서비스는 체중 (kg)과 키 (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);

다음으로에 client.js정의 된 SOAP 서비스를 사용할 파일을 만듭니다 server.js. 이 파일은 SOAP 서비스에 대한 인수를 제공하고 SOAP의 서비스 포트 및 엔드 포인트로 URL을 호출합니다.

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

wsdl 파일은 원격 웹 서비스에 액세스하는 방법을 정의하는 데이터 교환을위한 xml 기반 프로토콜입니다. wsdl 파일 호출bmicalculator.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>

도움이되기를 바랍니다.


필요한 엔드 포인트의 수에 따라 수동으로 수행하는 것이 더 쉬울 수 있습니다.

나는 10 개의 라이브러리 "soap nodejs"를 시도했다. 마침내 수동으로한다.


I successfully used "soap" package (https://www.npmjs.com/package/soap) on more than 10 tracking WebApis (Tradetracker, Bbelboon, Affilinet, Webgains, ...).

Problems usually come from the fact that programmers does not investigate to much about what remote API needs in order to connect or authenticate.

For instance PHP resends cookies from HTTP headers automatically, but when using 'node' package, it have to be explicitly set (for instance by 'soap-cookie' package)...


You may also look at the easysoap npm - https://www.npmjs.org/package/easysoap -or- some of these: https://nodejsmodules.org/tags/soap

https://nodejsmodules.org/pkg/express-soap2json


I used the node net module to open a socket to the webservice.

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

Send soap requests

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

Parse soap response, i used module - 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();
        }
    }
});

Hope it helps someone


Adding to Kim .J's solution: you can add preserveWhitespace=true in order to avoid a Whitespace error. Like this:

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

You can use wsdlrdr also. EasySoap is basically rewrite of wsdlrdr with some extra methods. Be careful that easysoap doesn't have the getNamespace method which is available at wsdlrdr.


For those who are new to SOAP and want a quick explanation and guide, I strongly recommend this awesome medium article.

You can also use node-soap package, with this simple tutorial.

참고URL : https://stackoverflow.com/questions/8655252/node-js-how-to-consume-soap-xml-web-service

반응형