Node.js:如何使用 SOAP XML Web 服务

Posted

技术标签:

【中文标题】Node.js:如何使用 SOAP XML Web 服务【英文标题】:Node.js: how to consume SOAP XML web service 【发布时间】:2012-01-29 03:03:13 【问题描述】:

我想知道使用 node.js 使用 SOAP XML Web 服务的最佳方式是什么

谢谢!

【问题讨论】:

如果您使用 node-soap 并弄清楚如何使用它,您能帮我创建一个 wsdl。是否有生成器或如何编写 wsdl 的好教程。 ***.com/questions/32480481/… 如果您需要 .NET WCF 服务调用的示例,请查看我的回答 ***.com/a/63351804/1370029 【参考方案1】:

你没有那么多选择。

您可能想要使用以下之一:

node-soap strong-soap(重写node-soap) easysoap

【讨论】:

谢谢。由于 node-expat 安装失败,node-soap 安装出现问题 =( 你需要外籍开发头文件来构建它 我发现了关于标题的问题,但我不知道我应该从哪里得到它我应该把它放在哪里编译,请你解释一下吗? 也许你可以通过你的操作系统的包管理工具来获得它们。例如在 Ubuntu 上 sudo apt-get install libexpat1-dev @RobertBroden,感谢您的更新。请下次继续编辑答案(或建议编辑)!【参考方案2】:

我认为另一种选择是:

使用 SoapUI (http://www.soapui.org) 等工具记录输入和输出 xml 消息 使用节点请求 (https://github.com/mikeal/request) 形成输入 xml 消息以将请求发送 (POST) 到 Web 服务(请注意,标准 javascript 模板机制,例如 ejs (http://embeddedjs.com/) 或 mustache (https://github.com/janl/mustache.js) 可以在这里帮助你),最后 使用 XML 解析器将响应数据反序列化为 JavaScript 对象

是的,这是一种相当肮脏和低级的方法,但它应该可以正常工作

【讨论】:

遗憾的是,这是使用 Node.js 与 SOAP 交互的最可靠方法。我还没有找到一个能够在我必须使用的少数 API 上正确发出 soap 请求的单个 soap 库。 100% 脏,但让我得到结果))) 形成输入 xml` 到底是什么意思? 是的,仍然可以确认,上述库都不是完美的。 我认为“Form input xml”意味着只给出“text/xml”的Content-Type【参考方案3】:

如果 node-soap 不适合您,只需使用 node request 模块,然后在需要时将 xml 转换为 json。

我的请求不适用于 node-soap,除了付费支持之外,我不提供对该模块的支持,这超出了我的资源范围。所以我做了以下事情:

    在我的 Linux 机器上下载了SoapUI。 已将 WSDL xml 复制到本地文件curl http://192.168.0.28:10005/MainService/WindowsService?wsdl > wsdl_file.xml 在 SoapUI 中,我转到 File > New Soap project 并上传了我的 wsdl_file.xml。 在导航器中,我展开其中一项服务并右键单击 请求并点击Show Request Editor

我可以从那里发送一个请求并确保它有效,我还可以使用Rawhtml 数据来帮助我构建一个外部请求。

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> 

我使用上面的构建了以下noderequest

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 而不是 SOAPUI 生成的端点。感谢上面的代码。【参考方案4】:

我设法使用了 soap、wsdl 和 Node.js 你需要用npm install soap安装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 文件,该文件将使用server.js 定义的soap 服务。此文件将为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 的数据交换协议,它定义了如何访问远程 Web 服务。调用你的 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>

希望对你有帮助

【讨论】:

非常感谢。但是,我不得不删除“res.send(response);”来自客户端和服务器文件最后一行的“`”。【参考方案5】:

我发现使用 Node.js 将原始 XML 发送到 SOAP 服务的最简单方法是使用 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。

但是,如果您只想通过 Node.js 与 SOAP 服务交互并进行常规 SOAP 调用,而不是发送原始 xml,请使用 Node.js 库之一。我喜欢node-soap。

【讨论】:

#Halfstop ,你能告诉我如何使用 node-soap 发出 POST 请求吗? @Abhisheksaini 上面的例子是一个帖子。 @Halfstop 请告诉我如何在请求中包含 SOAPAction。【参考方案6】:

根据您需要的端点数量,手动操作可能更容易。

我已经尝试了 10 个库“soap nodejs”,我终于手动完成了。

使用节点请求 (https://github.com/mikeal/request) 形成输入 xml 消息以将请求发送 (POST) 到 Web 服务 使用 xml2j (https://github.com/Leonidas-from-XIV/node-xml2js) 解析响应

【讨论】:

我尝试使用 node-soap 来访问 wsdl 路由,但它不起作用,我一直收到错误,尽管在 php 中同样有效 你能回答我关于你是如何做到的问题***.com/questions/39943122/…【参考方案7】:

我在 10 多个跟踪 WebApi(Tradetracker、Bbelboon、Affilinet、Webgains 等)上成功使用了“soap”包 (https://www.npmjs.com/package/soap)。

问题通常来自这样一个事实,即程序员没有深入研究远程 API 需要什么才能进行连接或验证。

例如 PHP 会自动从 HTTP 标头重新发送 cookie,但是当使用 'node' 包时,必须显式设置(例如通过 'soap-cookie' 包)...

【讨论】:

使用soap-cookie 帮助我绕过了我在节点中遇到的身份验证问题,非常感谢!【参考方案8】:

我使用 node net 模块打开了一个到 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);          
    
);

发送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;
    

解析soap响应,我使用了模块——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();
        
    
);

希望对某人有所帮助

【讨论】:

你为什么要这样做而不是使用 http 模块?【参考方案9】:

您还可以查看 easysoap npm - https://www.npmjs.org/package/easysoap -或者-

https://www.npmjs.com/package/express-soap2json

【讨论】:

【参考方案10】:

添加到Kim .J's solution:您可以添加preserveWhitespace=true 以避免出现空白错误。像这样:

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

【讨论】:

【参考方案11】:

您也可以使用 wsdlrdr。 EasySoap 基本上是用一些额外的方法重写了 wsdlrdr。 请注意,easysoap 没有 wsdlrdr 提供的 getNamespace 方法。

【讨论】:

【参考方案12】:

如果您只需要一次性转换,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

【讨论】:

【参考方案13】:

对于那些刚接触SOAP 并想要快速解释和指导的人,我强烈推荐这个很棒的article。

你也可以使用node-soappackage,这个简单的tutorial。

【讨论】:

提供的链接已不存在。 @JohnMelodyMelissa我刚刚修好了,谢谢。 没问题的朋友。【参考方案14】:

在我看来,避免使用 nodejs 查询 SOAP API。

两种选择:

    如果您是 SOAP API 的所有者,请让它同时处理 xml 和 json 请求,因为 javascript 可以很好地处理 json。

    在 php 中实现一个 API 网关(因为 php 可以很好地处理 SOAP)。网关会将您的输入作为 json 接收,然后在 xml 中查询 SOAP API 并将 xml 响应转换为 json。

【讨论】:

【参考方案15】:

这对我来说就像一个魅力

简单的肥皂请求

https://www.npmjs.com/package/easy-soap-request

简单明了

【讨论】:

【参考方案16】:

我有一个使用前缀 - 命名空间的 web 服务,但无法使其与 node-soap 一起使用。

所以我尝试了 axios post 方法。

转到浏览器并粘贴来自 axios 的 url 信息:https://somewebservice.company.com.br/WCF/Soap/calc.svc?wsdl

向下滚动,直到看到您感兴趣的 Soap 操作名称。

然后复制操作soapAction = "http://xyzxyzxyz/xyz/xyz/ObtenerSaldoDeParcelaDeEmprestimo"

在 axiosCall 标头中。

const axiosCall = require('axios')
const xml2js = require('xml2js')

let xml = `<soapenv:Envelope 
                xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                xmlns:tem="http://pempuri.org/" 
                xmlns:ser="http://schemas.example.org/2004/07/MyServices.Model">
            
            <soapenv:Header/>
                <soapenv:Body>
                
                <tem:DocumentState>
                <tem:DocumentData>
                     <ser:ID>0658</ser:ID>
                     <ser:Info>0000000001</ser:Info>
               </tem:DocumentData>
               </tem:DocumentState>
                
                </soapenv:Body>
            </soapenv:Envelope>         

let url = 'https://somewebservice.company.com.br/WCF/Soap/calc.svc?wsdl'

axiosCall.post( url,
            xml,
            
                headers: 
                    'Content-Type': 'text/xml',
                    SOAPAction: 'http://xyzxyzxyz/xyz/xyz/ObtenerSaldoDeParcelaDeEmprestimo'
                
            )
            .then((response)=>
                 // xml2js to parse the xml response from the server 
                 // to a json object and then be able to iterate over it.

                 xml2js.parseString(response.data, (err, result) => 
                    
                    if(err) 
                        throw err;
                    
                    console.log(result)
                
                                        
            )

                
            )
            .catch((error)=>
                
                console.log(error)
                
            )

【讨论】:

以上是关于Node.js:如何使用 SOAP XML Web 服务的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中更改soap xml Web 服务?

Node.js 使用 soap 模块请求 WebService 服务接口

如何使用来自iPhone应用程序的SOAP请求将图像+ xml上传到Web服务器

如何获取 WCF Web 服务请求的 XML SOAP 请求?

如何自定义 SOAP Web 服务命名空间

如何使用Karate验证给定XML的SOAP服务XML文件