【问题标题】:SOAP with Node.js & arguments spreading带有 Node.js 和参数传播的 SOAP
【发布时间】:2018-01-29 13:27:18
【问题描述】:

我必须使用一个 SOAP API,它基本上是为 PHP 设计的,并且一直是 PHP 客户端的用户。问题是,我使用 Node.js,遇到了一个我无法处理的问题。 这是“可能工作”代码的一部分:

<?php
try {
    $client = new SoapClient(null, array(
        'location' => "https://my-soap-server.com/_soap/server.php",
        'uri' => "https://my-soap-server.com",
        'encoding' => 'ISO-8859-1'
    ));
    $result = $client->myMethod('aaaa', 'bbbb', 'cccc');
    var_dump($result);
}
catch (SoapFault $fault) {
    trigger_error("SOAP Fault: (faultcode: {$fault->faultcode}, faultstring:{$fault->faultstring})", E_USER_ERROR);
}

如您所见,参数以特定顺序传递给 myMethod,而不是作为对象。 使用节点的肥皂客户端(节点肥皂或强肥皂),参数 2 必须是回调,它可以给出非常像这样的代码:(假设文档给我的字段 1 应该是“登录”等)

const soap = require('soap');

soap
    .createClientAsync('http://my-soap-server.com')
    .then((client) => client.myMethod({
        login: 'aaaa',
        password: 'bbbb',
        randomVar: 'cccc',
    }, (error, result) => {
        if (error) {
            console.error(error);
            process.exit(1);
        }
        console.log(result);
        process.exit(0);
    })
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

好吧,我没有任何错误,但 API 没有按照预期执行。 所以,我想问题是服务器不期望一个带有键的对象,而是参数,按一定的顺序传播,就像在 PHP 中一样。有没有办法用 Node.js 重现它?

我希望我已经足够清楚了。

非常感谢您的帮助。

编辑:使用WSDL 可能更容易,我想要使用的方法是 Ajout_BDD。

编辑 2:好吧,经过进一步调查,看起来来自 PHP 的 SOAP 请求和来自 Node.js 的请求在格式上确实不同。 因此,我通过使用来自节点的“请求”库并从工作的 PHP 请求制作模板,使它变得更简单(不幸的是,更脏)。 仅供参考,您可以使用以下代码转储 PHP SOAP 请求:

$client = new SoapClient("http://127.0.0.1:2018/test/test2?WSDL", array(
    'trace' => 1
));
[...]
var_dump($client->__getLastRequest());

您也可以通过这种方式转储 Node SOAP 请求:

soap.createClientAsync('http://my-soap-server/hello?WSDL', (error, client) => client.myMethod({
    login: 'aaaa',
    password: 'bbbb',
    randomVar: 'cccc',
}, (error, result) => {
    [...]
    console.log(client.lastRequest);
}));

然后只需使用您最喜欢的比较器来查看您的调用之间有什么不同。

【问题讨论】:

  • 这是一个棘手的问题,如果无法访问相关服务,很难准确看出 Node.js SOAP 请求的问题所在。在这种情况下真正有用的是查看实际 Web 流量的踪迹。像 WireShark 这样的东西在这里真的很有用,你可以看到你从 PHP 发出的请求是什么样的,并将它与你在 Node.js 中的请求进行比较。我遇到过这样的问题,我可以很快看出这两个 SOAP 调用之间有什么不同。
  • 这是解决问题的好方法,能够检查确切的 SOAP 请求以查看差异是很有用的。

标签: node.js soap


【解决方案1】:

我已经测试了链接中提供的 WSDL,对 Ajout_BDD 过程的 SOAP 调用将涉及如下所示的 HTTP 帖子:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:typens="urn:mdworks">
    <soap:Body>
        <typens:Ajout_BDD>
            <login>loginValue</login>
            <moddepasse>moddepasseValue</moddepasse>
            <bdd>bddValue</bdd>
            <ligne>
                <typens:someField>someFieldValue</typens:someField>
            </ligne>
        </typens:Ajout_BDD>
    </soap:Body>
</soap:Envelope>

响应应该是这样的:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:typens="urn:mdworks">
    <soap:Body>
        <typens:Ajout_BDDResponse>
            <typens:output>
                <typens:Ajout_BDDReturn>true</typens:Ajout_BDDReturn>
            </typens:output>
        </typens:Ajout_BDDResponse>
    </soap:Body>
</soap:Envelope>

对于需要 PHP 客户端调用它的服务,应该没有什么特别的内容。在 Node.js 中,您的客户端代码应如下所示:

"use strict";

var url = 'http://localhost:8001/mdworksService';
var wsdlFileName = 'example-service-original.wsdl';

const soap = require('soap');
const path = require('path');

soap
    .createClientAsync(path.join(__dirname, wsdlFileName), {endpoint: url})
    .then((client) => client.Ajout_BDD({
        login: 'loginValue', moddepasse: 'moddepasseValue', bdd: 'bddValue', ligne: { someField: 'someFieldValue'}
    }, (error, result) => {
        if (error) {
            console.error(error);
            process.exit(1);
        }
        console.log(result);
        process.exit(0);
    }))
    .catch( (error) => {
        console.error(error);
        process.exit(1);
    });

您需要将 url 替换为服务的实际 URL,并创建 WSDL 文件(使用您链接到的 WSDL)。为了测试您的客户端代码,创建此服务的 Node.js Mock 很容易。您可以执行以下操作:

"use strict";

var soap = require('soap');
var http = require('http');

var service = {
    mdworksService: {
        MDWORKSPort: {
            Ajout_BDD : function(args) {
                console.log('Calling Ajout_BDD: args: ' + JSON.stringify(args));
                return { output: { Ajout_BDDReturn : true } };
            }
        }
    }
}

var xml = require('fs').readFileSync('example-service-original.wsdl', 'utf8');

var server = http.createServer(function(request,response) {
    response.end("404: Not Found: "+request.url);
});

server.listen(8001);
var soapServer = soap.listen(server, '/mdworksService', service, xml);
soapServer.log = function(type, data) {
    // type is 'received' or 'replied'
    console.log(new Date().toISOString() + ": " + type + ': ' + data);
};

同样,您需要将 WSDL 文件包含在与服务器相同的目录中。这种方法对于测试 SOAP 客户端非常有用。

【讨论】:

    猜你喜欢
    • 2013-01-28
    • 1970-01-01
    • 2016-05-10
    • 2016-05-09
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 1970-01-01
    相关资源
    最近更新 更多