Nœud.js: comment consommer le service Web XML SOAP
Je me demande Quelle est la meilleure façon de consommer le service Web XML SOAP avec node.js
Merci!
11 réponses
Vous n'avez pas beaucoup d'options.
Vous voudrez probablement utiliser l'un des éléments suivants:
- nœud-savon
-
fort-savon (réécriture de
node-soap
) - easysoap
Je pense qu'une solution serait de:
- utilisez un outil tel que SoapUI ( http://www.soapui.org ) pour enregistrer les messages xml d'entrée et de sortie
- utiliser la demande de noeud ( https://github.com/mikeal/request ) pour former un message xml d'entrée pour envoyer (poster) la demande au service web (notez que les mécanismes de template javascript standard tels que ejs ( http://embeddedjs.com/) ou moustache ( https://github.com/janl/mustache.js ) pourrait vous aider ici) et enfin
- utilisez un analyseur XML pour désérialiser les données de réponse aux objets JavaScript
Oui, c'est une approche plutôt sale et de bas niveau mais cela devrait fonctionner sans problèmes
La façon la plus simple que j'ai trouvée d'envoyer simplement du XML brut à un service SOAP en utilisant Node.js est d'utiliser le nœud.implémentation http js. Il ressemble à ceci.
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();
Vous auriez défini la variable xml comme xml brut sous la forme d'une chaîne.
Mais si vous voulez juste interagir avec un service SOAP via Node.js et effectuer des appels SOAP réguliers, par opposition à l'envoi de xml brut, utilisez l'un des nœuds.les librairies js. J'aime nœud de savon.
J'ai réussi à utiliser soap, WSDL et Node.js
Vous devez installer soap avec npm install soap
Créez un serveur de nœuds appelé server.js
qui définira le service soap à utiliser par un client distant. Ce service de savon calcule L'indice de masse corporelle basé sur le poids (kg) et la taille (m).
var soap = require('soap');
var express = require('express');
var 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
**/
var service = {
BMI_Service : {
BMI_Port :{
calculateBMI:function(args){
//console.log(Date().getFullYear())
var year = new Date().getFullYear();
var n = (args.weight)/(args.height*args.height);
console.log(n);
return {bmi: n};
}
}
}
}
// xml data is extracted from wsdl file created
var xml = require('fs').readFileSync('./bmicalculator.wsdl','utf8');
//create an express server and pass it to a soap server
var server = app.listen(3030,function(){
var host = "127.0.0.1";
var port = server.address().port;
});
`soap.listen(server,'/bmicalculator',service,xml);
Ensuite, créez un fichier client.js
qui consommera le service soap défini par server.js
. Ce fichier fournira des arguments pour le service soap et appellera l'url avec les ports et les points de terminaison du service SOAP.
var express = require('express');
var soap = require('soap');
var url = "http://localhost:3030/bmicalculator?wsdl";
var 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);
}
})
}
});
Votre le fichier wsdl est un protocole basé sur xml pour l'échange de données qui définit comment accéder à un service web distant. Appelez votre fichier 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>
J'espère que ça aide
Selon le nombre de points de terminaison dont vous avez besoin, il peut être plus facile de le faire manuellement.
J'ai essayé 10 bibliothèques "soap nodejs" je le fais finalement manuellement.
- utiliser la demande de noeud ( https://github.com/mikeal/request ) pour former un message xml d'entrée pour envoyer (poster) la demande au service web
- utiliser xml2j ( https://github.com/Leonidas-from-XIV/node-xml2js ) pour analyser la réponse
Si node-soap
ne fonctionne pas pour vous, utilisez simplementnode
request
module, puis convertir le xml en json si nécessaire.
Ma demande ne fonctionnait pas avec node-soap
et il n'y a pas de support pour ce module au-delà du support payé, qui était au-delà de mes ressources. J'ai donc fait ce qui suit:
- téléchargé SoapUI sur ma machine Linux.
- copié le fichier xml WSDL dans un fichier local
curl http://192.168.0.28:10005/MainService/WindowsService?wsdl > wsdl_file.xml
- Dans SoapUI je suis allé à
File > New Soap project
et téléchargé monwsdl_file.xml
. - dans le navigateur j'ai élargi l'un des services et fait un clic droit
la requête et cliqué sur
Show Request Editor
.
À partir de là, je pourrais envoyer une requête et m'assurer que cela fonctionnait et je pourrais également utiliser les données Raw
ou HTML
pour m'aider à construire une requête externe.
Raw de SoapUI pour ma demande
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 à partir 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>
J'ai utilisé ce qui précède pour construire ce qui suit 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);
J'ai utilisé avec succès le paquet "soap" (https://www.npmjs.com/package/soap ) sur plus de 10 webapis de suivi (Tradetracker, Bbelboon, Affilinet, Webgains,...).
Les problèmes viennent généralement du fait que les programmeurs n'enquêtent pas beaucoup sur les besoins de L'API distante pour se connecter ou s'authentifier.
Par exemple, PHP renvoie automatiquement les cookies des en-têtes HTTP, mais lors de l'utilisation du paquet 'node', il doit être explicitement défini (par exemple par "savon-cookie" paquet)...
Vous pouvez également regarder le npm easysoap - https://www.npmjs.org/package/easysoap -ou - certains de ces: https://nodejsmodules.org/tags/soap
J'ai utilisé le module node net pour ouvrir un socket au 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);
}
});
Envoyer des requêtes soap
/* 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;
}
Analyser la réponse soap, j'ai utilisé le 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();
}
}
});
J'espère que ça aide quelqu'un
Ajouter à Kim .Solution de J : Vous pouvez ajouter preserveWhitespace=true
afin d'éviter une erreur D'Espace. Comme ceci:
soap.CreateClient(url,preserveWhitespace=true,function(...){
Vous pouvez également utiliser wsdlrdr. EasySoap est essentiellement la réécriture de wsdlrdr avec quelques méthodes supplémentaires. Veillez à ce qu'easysoap n'ait pas la méthode getNamespace disponible sur wsdlrdr.