Node.js: как использовать веб-службу SOAP XML


99

Интересно, как лучше всего использовать веб-службу SOAP XML с помощью node.js

Спасибо!


Если вы используете node-soap и выяснили, как его использовать, не могли бы вы помочь мне с созданием файла wsdl. Есть ли генератор или хороший учебник по написанию файла wsdl. stackoverflow.com/questions/32480481/…
Энди Гига

Если вам нужен пример вызова службы .NET WCF, посмотрите мой ответ stackoverflow.com/a/63351804/1370029
Алиаксей Манюк,

Ответы:


83

У вас не так много вариантов.

Вероятно, вы захотите использовать одно из:


3
Спасибо. возникли проблемы с установкой node-soap из-за сбоя установки node-
expat

Для его создания вам понадобятся заголовки для разработчиков
Juicy Scripter

Я обнаружил, что проблема связана с заголовками, но я не знаю, где мне ее взять, где мне поместить ее для компиляции, не могли бы вы объяснить, пожалуйста?
WHITECOLOR

1
Вероятно, вы можете получить их с помощью инструментов управления пакетами для вашей ОС. Например, на Ubuntusudo apt-get install libexpat1-dev
Juicy Scripter

1
@RobertBroden, спасибо за обновление. Пожалуйста, в следующий раз отредактируйте ответ (или предложите исправление)!
Juicy Scripter

31

Думаю, альтернативой было бы:

  • используйте такой инструмент, как SoapUI ( http://www.soapui.org ) для записи входных и выходных XML-сообщений
  • используйте запрос узла ( https://github.com/mikeal/request ) для формирования входного XML-сообщения для отправки (POST) запроса веб-службе (обратите внимание, что стандартные механизмы шаблонов javascript, такие как ejs ( http://embeddedjs.com / ) или усы ( https://github.com/janl/mustache.js ) могут вам здесь помочь) и, наконец,
  • использовать синтаксический анализатор XML для десериализации данных ответа на объекты JavaScript

Да, это довольно грязный и низкоуровневый подход, но он должен работать без проблем.


4
К сожалению, это самый надежный способ взаимодействия с SOAP с Node.js. Я еще не нашел ни одной библиотеки мыла, которая должным образом выполняла бы запросы мыла для нескольких API, которые мне нужно использовать.
AlbertEngelB

1
100% грязный, но довел меня до результата)))
markkillah 01

что вы все имеете в виду именно под формой input xml`?
timaschew

да, могу подтвердить, что ни одна из вышеупомянутых библиотек не работает идеально.
someUser

Я думаю, что «Ввод формы xml» означает просто предоставление Content-Type «text / xml»
SSH

22

Если у node-soapвас не работает, просто используйте node requestмодуль, а затем при необходимости конвертируйте xml в json.

Мой запрос не работал, node-soapи для этого модуля нет поддержки, кроме платной поддержки, которая была вне моих ресурсов. Итак, я сделал следующее:

  1. загрузил SoapUI на свою Linux-машину.
  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чтобы помочь мне создать внешний запрос.

Raw из 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)

XML из 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> 

Я использовал это для создания следующего 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);

спасибо @jtlindsey. Но я получаю метод 405, который не разрешен как response.statusCode, response.statusMessage. Вы случайно не знаете, как это исправить?
Суджой

Возникла проблема с моим URL. Я использовал исходный URL-адрес вместо конечной точки, созданной SOAPUI. Спасибо за приведенный выше код.
Суджой

17

Мне удалось использовать мыло, wsdl и Node.js Вам нужно установить мыло с npm install soap

Создайте сервер узла, server.jsкоторый будет определять мыльную службу, которая будет использоваться удаленным клиентом. Этот мыльный сервис рассчитывает индекс массы тела на основе веса (кг) и роста (м).

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файл, который будет использовать службу мыла, определяемую server.js. Этот файл предоставит аргументы для мыльной службы и вызовет URL-адрес с портами и конечными точками службы 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);
      }
    });
  }
});

Ваш файл wsdl - это протокол на основе xml для обмена данными, который определяет, как получить доступ к удаленной веб-службе. Назовите ваш файл 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>

Надеюсь, поможет


1
Огромное спасибо. Однако мне пришлось удалить "res.send (response);" от клиента и "" "в последней строке файла сервера.
Субхаши

13

Самый простой способ, который я нашел, просто отправить необработанный XML в службу SOAP с помощью Node.js, - это использовать реализацию 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 в форме строки.

Но если вы просто хотите взаимодействовать со службой SOAP через Node.js и делать регулярные вызовы SOAP, а не отправлять необработанный XML, используйте одну из библиотек Node.js. Мне нравится узел-мыло .


1
#Halfstop, не могли бы вы рассказать мне, как сделать POST-запрос с помощью node-soap?
Abhishek saini

@Abhisheksaini приведенный выше пример - это пост.
Halfstop

@Halfstop Скажите, пожалуйста, как включить SOAPAction в запрос.
Sohail

12

В зависимости от количества необходимых конечных точек может быть проще сделать это вручную.

Я пробовал 10 библиотек «мыло nodejs», наконец, делаю это вручную.


Я попробовал node-soap для доступа к маршруту wsdl, но он не работает, я продолжаю получать ошибку, хотя то же самое работает в php. Можете ли вы ответить на мой вопрос о том, как вы это сделали stackoverflow.com/questions/39943122/…
Ammar Ajmal

8

Я успешно использовал пакет «мыло» ( https://www.npmjs.com/package/soap ) на более чем 10 отслеживающих WebApis (Tradetracker, Bbelboon, Affilinet, Webgains, ...).

Проблемы обычно возникают из-за того, что программисты не уделяют много внимания тому, что удаленному API нужно для подключения или аутентификации.

Например, PHP автоматически пересылает файлы cookie из заголовков HTTP, но при использовании пакета 'node' он должен быть явно установлен (например, пакетом 'soap-cookie') ...


использование мыльных файлов cookie помогло мне обойти проблему с аутентификацией, которая возникла в узле, большое спасибо!
nicolasdaudin 08


5

Я использовал сетевой модуль узла, чтобы открыть сокет для веб-службы.

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

Отправить запросы на мыло

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

Разобрать ответ мыла, я использовал модуль - 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();
        }
    }
});

Надеюсь, это кому-то поможет


1
почему бы вы сделали это вместо использования модуля http?
Уилл Манн

0

Добавление к решению Kim .J : вы можете добавить preserveWhitespace=true, чтобы избежать ошибки пробела. Как это:

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

0

Вы также можете использовать wsdlrdr. EasySoap в основном переписывает wsdlrdr с некоторыми дополнительными методами. Будьте осторожны, у easysoap нет метода getNamespace, доступного на wsdlrdr.



0

Если вам просто нужно одноразовое преобразование, https://www.apimatic.io/dashboard?modal=transform позволяет сделать это, создав бесплатную учетную запись (без привязки, это просто сработало для меня).

Если вы трансформируетесь в Swagger 2.0, вы можете создать js lib с

$ 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.