Perl から JAX-WS な Web サービスへの通信方法
前回の続き。
Perl をクライアントとして、JAX-WS な Web サービスにアクセスする。
Perl
Perl は SOAP::Lite を使用すれば良いらしいが、中々一筋縄でいかず一番ハマった。
まずはドキュメントにあるように素直にやってみた。
#!/usr/bin/env perl use strict; use warnings; use SOAP::Lite; my $client = SOAP::Lite->service('http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl'); my $result = $client->add(1, 2); warn Dumper $result;
$VAR1 = undef;
デバッグオプションをつけてみる。
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use SOAP::Lite +trace => [qw(debug)]; my $client = SOAP::Lite->service('http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl'); $client->readable(1); my $result = $client->add(1, 2); warn Dumper $result;
SOAP::Transport::HTTP::Client::send_receive: POST http://localhost:8084/CalculatorWSApplication/CalculatorWS HTTP/1.1 Accept: text/xml Accept: multipart/* Accept: application/soap Content-Length: 850 Content-Type: text/xml; charset=utf-8 SOAPAction: "" <?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://org.me.calculator/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <tns:add> <c-gensym3 xsi:type="xsd:int">1</c-gensym3> <c-gensym5 xsi:type="xsd:int">2</c-gensym5> </tns:add> </soap:Body> </soap:Envelope> SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 500 Internal Server Error Connection: close Date: Tue, 03 Aug 2010 09:43:23 GMT Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Client-Date: Tue, 03 Aug 2010 09:43:23 GMT Client-Peer: 127.0.0.1:8084 Client-Response-Num: 1 <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope"> <faultcode>S:VersionMismatch</faultcode> <faultstring> Couldn't create SOAP message. Expecting Envelope in namespace http://schemas.xmlsoap.org/soap/envelope/, but got http://schemas.xmlsoap.org/wsdl/soap/ </faultstring> </S:Fault> </S:Body> </S:Envelope> $VAR1 = undef;
Internal Server Error を起こしている…。
送信しているリクエストヘッダの名前空間がおかしいとエラーが出てる。
色々調べて結果以下のように名前空間を追加すれば良いらしい。
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use SOAP::Lite +trace => [qw(debug)]; my $client = SOAP::Lite->service('http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl'); $client->readable(1); $client->ns('http://schemas.xmlsoap.org/soap/envelope/', 'ns'); my $result = $client->add(1, 2); warn Dumper $result;
SOAP::Transport::HTTP::Client::send_receive: POST http://localhost:8084/CalculatorWSApplication/CalculatorWS HTTP/1.1 Accept: text/xml Accept: multipart/* Accept: application/soap Content-Length: 898 Content-Type: text/xml; charset=utf-8 SOAPAction: "" <?xml version="1.0" encoding="UTF-8"?> <ns:Envelope_ xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/" ns:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://org.me.calculator/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ns:Body> <tns:add> <c-gensym3 xsi:type="xsd:int">1</c-gensym3> <c-gensym5 xsi:type="xsd:int">2</c-gensym5> </tns:add> </ns:Body> </ns:Envelope> SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK Connection: close Date: Tue, 03 Aug 2010 09:47:01 GMT Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Client-Date: Tue, 03 Aug 2010 09:47:01 GMT Client-Peer: 127.0.0.1:8084 Client-Response-Num: 1 <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:addResponse xmlns:ns2="http://org.me.calculator/"> <return>0</return> </ns2:addResponse> </S:Body> </S:Envelope> $VAR1 = '0';
Internal Server Error は消えたが、期待する結果とは異った。
<tns:add> <c-gensym3 xsi:type="xsd:int">1</c-gensym3> <c-gensym5 xsi:type="xsd:int">2</c-gensym5> </tns:add>
原因は上記のように
PHP ではどのようなリクエストを送っているか比較してみた。
<?php ini_set('soap.wsdl_cache_enabled', '0'); $uri = 'http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl'; $client = new SoapClient($uri, array('trace' => 1)); $result = $client->add(array('i' => 1, 'j' => 10)); echo $client->__getLastRequest();
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://org.me.calculator/"> <SOAP-ENV:Body> <ns1:add> <i>1</i> <j>10</j> </ns1:add> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
シンプルな形で送信している。
色々調査とトライアンドエラーを繰り返した結果、SOAP::Lite を使用した場合、以下のようにすればいけた。
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use SOAP::Lite +trace => [qw(debug)]; my $client = SOAP::Lite->service('http://localhost:8084/CalculatorWSApplication/CalculatorWS?wsdl'); $client->readable(1); $client->ns('http://schemas.xmlsoap.org/soap/envelope/', 'ns'); my $args1 = SOAP::Data->name('i')->value(1); my $args2 = SOAP::Data->name('j')->value(2); my $result = $client->add($args1, $args2); warn Dumper $result;
SOAP::Transport::HTTP::Client::send_receive: POST http://localhost:8084/CalculatorWSApplication/CalculatorWS HTTP/1.1 Accept: text/xml Accept: multipart/* Accept: application/soap Content-Length: 870 Content-Type: text/xml; charset=utf-8 SOAPAction: "" <?xml version="1.0" encoding="UTF-8"?> <ns:Envelope xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/" ns:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://org.me.calculator/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ns:Body> <tns:add> <i xsi:type="xsd:int">1</i> <j xsi:type="xsd:int">2</j> </tns:add> </ns:Body> </ns:Envelope> SOAP::Transport::HTTP::Client::send_receive: HTTP/1.1 200 OK Connection: close Date: Tue, 03 Aug 2010 10:38:22 GMT Server: Apache-Coyote/1.1 Content-Type: text/xml;charset=utf-8 Client-Date: Tue, 03 Aug 2010 10:38:22 GMT Client-Peer: 127.0.0.1:8084 Client-Response-Num: 1 <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:addResponse xmlns:ns2="http://org.me.calculator/"> <return>3</return> </ns2:addResponse> </S:Body> </S:Envelope> $VAR1 = '3';
ちゃんと add の箇所のタグが、i と j という風に Java のパラメータと同じ値になっている。
なお、配列を(Java の List)を送りたい場合は、以下のようにする。
my $args3 = SOAP::Data->name('params')->value(100, 200); my $result2 = $client->addList($args3); warn Dumper $result2;
リクエストはこんな感じになった。
<?xml version="1.0" encoding="UTF-8"?> <ns:Envelope xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:ns="http://schemas.xmlsoap.org/soap/envelope/" ns:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://org.me.calculator/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <ns:Body> <tns:addList> <params xsi:type="xsd:int">100</params> <params xsi:type="xsd:int">200</params> </tns:addList> </ns:Body> </ns:Envelope>
$VAR1 = '300';