gpt4 book ai didi

Perl SOAP::Lite 接口(interface)到 .NET 上的供应商 API

转载 作者:行者123 更新时间:2023-12-04 16:54:37 25 4
gpt4 key购买 nike

经常阅读,第一次提问。

我正在将 Perl 与我们的一个供应商 (LogRhythm) 提供的 SOAP API 连接起来,但似乎遇到了一些障碍。

我已经能够与 API 交互,并且克服了我最初遇到的身份验证挑战。现在,当我需要向 SOAP 调用提供参数时,我在 SOAP Envelope Body 中遇到了 namespace 标记问题。

供应商提供的 API 是围绕 .NET 和 WCF 构建的。

我的原型(prototype)代码目前如下所示:

use strict;
no strict "refs";

use Data::Dumper;
use IO::Socket::SSL qw (SSL_VERIFY_NONE) ;
use SOAP::Lite;
use Tie::IxHash;

# Username and Password
my $sUID = "<API UserID>";
my $sPWD = "<API Password>";

# WSDL definition URI. Using a cached local copy using file:/... also works
my $LookupService_wsdl = 'https://melcapi01.soc.ipsec.net.au/LogRhythm.API/Services/LookupServiceBasicAuth.svc?singleWsdl';
my $lrns = 'http://www.logrhythm.com/webservices';

# Ensure that a consistent xmlns:soap value is used, without this we get inconsistent results.
$SOAP::Constants::PREFIX_ENV = 'SOAP-ENV';

# Don't validate SSL Certificate while testing
IO::Socket::SSL::set_defaults(SSL_verify_mode => "SSL_VERIFY_NONE");

# Construct the security header
my %authHash;
tie %authHash, "Tie::IxHash";
%authHash = (
Username => SOAP::Data->type( '' => $sUID )->prefix('wsse'),
Password => SOAP::Data->type( '' => $sPWD )->prefix('wsse'),
);

my $wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
my $securityHeader = SOAP::Header->new(
name => 'Security',
uri => $wsse,
prefix => 'wsse',
value => \SOAP::Data->new(
name => 'UsernameToken',
prefix => 'wsse',
value => \%authHash,
)
);

# Error handling
on_fault => sub { my($soap, $res) = @_;
die ref $res ? $res->faultstring : $soap->transport->status;
};

# Define the SOAP Instance
my $lrapi = SOAP::Lite
-> readable (1)
-> service($LookupService_wsdl)
-> on_action( sub {return $action});

# Set the default Namespace
$lrapi->default_ns($lrns);

# Actually get data from the LookupService
my $result;

# Build up the parameters
my @classificationType = ( SOAP::Data->new(name =>'classificationType', value => 2000));

$result = $lrapi->GetClassificationsByType($securityHeader);

print Dumper $result;

这会导致以下 SOAP 请求:
SOAPAction: "http://www.logrhythm.com/webservices/LookupService/GetClassificationsByType"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://www.logrhythm.com/webservices"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsa10="http://www.w3.org/2005/08/addressing"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>reporting</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:GetClassificationsByType>
<classificationType xsi:type="xsd:int">2000</classificationType>
<classificationTypeSpecified xsi:type="xsd:boolean">true</classificationTypeSpecified>
</tns:GetClassificationsByType>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

不返回任何结果。我已经使用 .NET WebService Studio 进行了一些挖掘和请求修复,并确定问题是由 SOAP 主体中元素上缺少 xmlns 标识符引起的。

SOAP 请求应如下所示:
SOAPAction: "http://www.logrhythm.com/webservices/LookupService/GetClassificationsByType"

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://www.logrhythm.com/webservices"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wsa10="http://www.w3.org/2005/08/addressing"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>reporting</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<tns:GetClassificationsByType xmlns="http://www.logrhythm.com/webservices">
<classificationType xsi:type="xsd:int">2000</classificationType>
<classificationTypeSpecified xsi:type="xsd:boolean">true</classificationTypeSpecified>
</tns:GetClassificationsByType>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

各种支持请求表明这应该通过手动设置 default_ns 来解决。然而,在 SOAP::Lite 对象上,这对我不起作用。

我已经挖掘了 SOAP::Lite 的来源(1.20) 看看是怎么回事,好像是 {'_use_default_ns'}属性,设置为 1在进行 SOAP 方法调用之前,似乎重置为 0在调用处理过程中。

我还尝试手动构建 SOAP::Lite 对象,目的是使用 call()获得所需结果的方法,但是,我认为我遇到了由于 service() 而自动添加的 namespace 数量的问题。我目前正在使用的机制。如果我想使用 call()方法似乎我无法使用 service() 设置对象.

有没有人有任何其他建议我可以尝试,因为我此时不知所措?

任何帮助将不胜感激。

免责声明:我不是程序员/开发人员,我是一名具有一定编程能力的高级安全工程师/顾问/架构师,所以如果我的代码结构不佳,我提前道歉。这也是我第一次尝试使用 SOAP。

最佳答案

这是一个有点hacky的解决方案。它挂接到您的 SOAP::Lite 客户端的传输层并修改每个传出请求。

我使用了通过谷歌搜索找到的随机 Web 服务,因此您可以复制和粘贴示例代码并在没有凭据的情况下运行它。 The service由美国国家气象局运营。在我的示例中,我使用他们的端点来返回美国邮政编码的经纬度坐标。

use strict;
use warnings 'all';
use feature 'say';
use SOAP::Lite;

my $client = SOAP::Lite->new(
proxy => 'http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php'
);
$client->service('http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl');

# the transport layer is a subclass of LWP::UserAgent
$client->transport->add_handler(
request_prepare => sub {
my ( $request, $ua, $h ) = @_;
my $content = $request->content;

# this is the content before modification
say 'before: ' . $content;

# modify the content with a simple regex substitution
$content =~ s{<LatLonListZipCode>}{<LatLonListZipCode xmlns="http://example.org">};
$request->content($content);

# so it doesn't throw a 'Content-Length header value
# was wrong, fixed' warning
$request->header( 'Content-Length' => length $content );

# this is the content after modification
say 'after: ' . $content;

# the return value is ignored
}
);

my $res = $client->LatLonListZipCode('90210');
say $res->result;

说明

这是有效的,因为 SOAP::Transport用于此类 SOAP 通信的层, SOAP::Transport::HTTP::Client , 是 LWP::UserAgent 的子类. UserAgent 非常灵活,提供了很多 different handlers对于某些事件。我们使用的是 request_prepare ,这允许我们更改 HTTP::Request在通过有线(或无线或其他方式)发送之前。

The handler is called before the request is sent and can modify the request any way it see fit. This can for instance be used to add certain headers to specific requests.



在我们添加的处理程序中,我们获取请求的内容并使用正则表达式替换将 xmlns 添加到 <LatLongListZipCode>标签。虽然 parsing XML with regex is not a good idea ,更改一些看起来像 XML 的文本是可以的,因为我们当时并不关心了解其中的内容。

由于请求已经构建,我们需要更新 Content-Length 的头字段。它会自动更新,但同时会发出警告。我们可以通过简单地更新它来省略它。

这是程序的输出,分为三个部分。

变更前的请求内容

<?xml version="1.0" encoding="UTF-8"?><soap:Envelope soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><LatLonListZipCode><c-gensym3 xsi:type="xsd:int">90210</c-gensym3></LatLonListZipCode></soap:Body></soap:Envelope>

变更后的请求内容

<?xml version="1.0" encoding="UTF-8"?><soap:Envelope soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><LatLonListZipCode xmlns="http://example.org"><c-gensym3 xsi:type="xsd:int">90210</c-gensym3></LatLonListZipCode></soap:Body></soap:Envelope>

回复内容

<?xml version='1.0'?><dwml version='1.0' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd'><latLonList>34.0995,-118.414</latLonList></dwml>

显然更改有效,请求仍在处理,我选择的服务不关心该 xmlns 属性。

为您的 Web 服务采用

对于您的用例,您必须确保只有不立即可用的请求才会被更改。如果所有这些都应该改变,它可能就这么简单。构建客户端后只需执行一次。

$lrapi->transport->add_handler(
request_prepare => sub {
my ( $request, $ua, $h ) = @_;
my $content = $request->content;

# modify the content with a simple regex substitution
$content =~ s{<tns:GetClassificationsByType>}{<tns:GetClassificationsByType xmlns="http://www.logrhythm.com/webservices">};
$request->content($content);

# so it doesn't throw a 'Content-Length header value was wrong, fixed' warning
$request->header( 'Content-Length' => length $content );
}
);

免责声明

正如我所说,这是一个务实的解决方案。但是 SOAP 非常复杂,而且很少有客户能把一切都做好。还有很多服务器做很多不太正确的事情。有时,务实是最好的行动方针。当然,服务器中的行为可能会改变,在这种情况下这可能会中断。但我相信这是值得冒的风险。

关于Perl SOAP::Lite 接口(interface)到 .NET 上的供应商 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39262470/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com