使用Savon在Ruby on Rails中调用SOAP在包络和主操作方面变得奇怪

时间:2017-07-07 09:32:03

标签: ruby-on-rails xml soap savon

在使用Savon.rb的rails项目中,我试图进行一个非常复杂的SOAP调用。至少复杂到Savon构建者的困难,所以我决定直接操作:xml。

我首先发起客户:

@client = Savon.client(
            :endpoint => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/BarcodeWebService.svc',
            :wsdl     => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl')

然后我以以下形式打电话:

@request = @client.build_request(:generate_barcode,
             xml: %Q{ ... see soap call (with ruby interpolation) ... } 

我添加了格式正确的l Time.now, format: :postnl_api字符串,其余字符串仍然是硬编码的。包括消息号。

以下是Savon在这种情况下实际调用的方式,使用@request.body检索。

我的应用程序中的SOAP调用

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:wsdl="http://tempuri.org/"
  xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode
    </Action>
    <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <UsernameToken>
        <Username>devc_!R4xc8p9</Username>
        <Password>xxxxxxxx</Password>
      </UsernameToken>
    </Security>
  </s:Header>
  <s:Body>
    <wsdl:GenerateBarcode>
      <d6p1:Customer>
        <d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
        <d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
      </d6p1:Customer>
      <d6p1:Barcode>
        <d6p1:Type>3S</d6p1:Type>
        <d6p1:Range>DEVC</d6p1:Range>
        <d6p1:Serie>1000000-2000000</d6p1:Serie>
      </d6p1:Barcode>
    </wsdl:GenerateBarcode>
  </s:Body>
</s:Envelope>

接下来是一个电话应该是什么样子,因为我看到这个电话在公司的沙箱环境中取得了成功。

SOAP调用应该是

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode</Action>
    <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:Username>devc_!R4xc8p9</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">xxxxxxxx</wsse:Password>
      </wsse:UsernameToken>
    </Security>
  </s:Header>
  <s:Body>
    <GenerateBarcode xmlns:d6p1="http://postnl.nl/cif/domain/BarcodeWebService/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://postnl.nl/cif/services/BarcodeWebService/">
      <d6p1:Message>
        <d6p1:MessageID>5</d6p1:MessageID>
        <d6p1:MessageTimeStamp>28-06-2017 14:15:41</d6p1:MessageTimeStamp>
      </d6p1:Message>
      <d6p1:Customer>
        <d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
        <d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
      </d6p1:Customer>
      <d6p1:Barcode>
        <d6p1:Type>3S</d6p1:Type>
        <d6p1:Range>DEVC</d6p1:Range>
        <d6p1:Serie>1000000-2000000</d6p1:Serie>
      </d6p1:Barcode>
    </GenerateBarcode>
  </s:Body>
</s:Envelope>

似乎关闭的主要事情(这也是使用Savon构建器btw的情况)是envelope的属性和主要操作的:generate_barcode形状及其属性。我不明白为什么我在wsdl:之前得到前缀GenerateBarcode

我告诉Savon拿走我的xml然后完全按照它构建它,但它不起作用。按原样发送我的版本会返回错误400

使用Chris的编辑

使用@Chris他的回答我能够进行以下调用:

设置通话

@client = Savon.client(
                 :endpoint                => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/BarcodeWebService.svc',
                 :wsdl                    => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
                 :log                     => true,
                 :wsse_auth               => [ENV['postnl_username'], ENV['postnl_password']],
                 :pretty_print_xml        => true,
                 :convert_request_keys_to => :camelcase,
                 :env_namespace           => :s)

     message =  {
                  "d6p1:Message" => {
                    "d6p1:MessageID" =>  "7",
                    "d6p1:MessageTimeStamp" => I18n.l( Time.now, format: :postnl_api)
                },
                  "d6p1:Customer" => {
                    "d6p1:CustomerCode" => "DEVC",
                    "d6p1:CustomerNumber" =>  "11223344"},
                    "d6p1:Barcode" => {
                      "d6p1:Type" => "3S",
                      "d6p1:Range" => "DEVC",
                      "d6p1:Serie" => "1000000-2000000" } 
                }
     @client.call(:generate_barcode, :message => message, :soap_header => { "Action" => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode"})

拨打

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://tempuri.org/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action>http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode</Action>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-1">
        <wsse:Username>devc_!R4xc8p9</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">098fd559930983af31ef6630a0bb0c1974156561</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </s:Header>
  <s:Body>
    <wsdl:GenerateBarcode>
      <d6p1:Message>
        <d6p1:MessageID>7</d6p1:MessageID>
        <d6p1:MessageTimeStamp>17-07-2017 22:13:35</d6p1:MessageTimeStamp>
      </d6p1:Message>
      <d6p1:Customer>
        <d6p1:CustomerCode>DEVC</d6p1:CustomerCode>
        <d6p1:CustomerNumber>11223344</d6p1:CustomerNumber>
      </d6p1:Customer>
      <d6p1:Barcode>
        <d6p1:Type>3S</d6p1:Type>
        <d6p1:Range>DEVC</d6p1:Range>
        <d6p1:Serie>1000000-2000000</d6p1:Serie>
      </d6p1:Barcode>
    </wsdl:GenerateBarcode>
  </s:Body>
</s:Envelope>

回复

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <s:Fault>
      <faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</faultcode>
      <faultstring xml:lang="en-US">The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.</faultstring>
    </s:Fault>
  </s:Body>
</s:Envelope>

1 个答案:

答案 0 :(得分:1)

好的,这有效(已验证)

@client = Savon.client(
             :wsdl                    => 'https://testservice.postnl.com/CIF_SB/BarcodeWebService/1_1/?wsdl',
             :log                     => true,
             :wsse_auth               => ['devc_!R4xc8p9', 'xxx'],
             :pretty_print_xml        => true,
             :convert_request_keys_to => :camelcase,
             :env_namespace           => :s,
             :namespace_identifier    => nil
            )

 message =  {
              "d6p1:Message" => {
                "d6p1:MessageID" =>  "10",
                "d6p1:MessageTimeStamp" => Time.now.strftime("%d-%m-%Y %H:%M:%S")
            },
              "d6p1:Customer" => {
                "d6p1:CustomerCode" => "DEVC",
                "d6p1:CustomerNumber" =>  "11223344"},
                "d6p1:Barcode" => {
                  "d6p1:Type" => "3S",
                  "d6p1:Range" => "DEVC",
                  "d6p1:Serie" => "1000000-2000000" } 
            }


attributes = { "xmlns:d6p1" => "http://postnl.nl/cif/domain/BarcodeWebService/", 
               "xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance", 
               "xmlns" => "http://postnl.nl/cif/services/BarcodeWebService/"}

@client.call(:generate_barcode, :attributes => attributes, 
             :message => message, 
             :soap_header => { "Action" => "http://postnl.nl/cif/services/BarcodeWebService/IBarcodeWebService/GenerateBarcode"})

所以诀窍是添加:namespace_identifier => nil并发送attributes。设置namespace_identifier会从wsdl ans属性中删除GenerateBarcode,在GenerateBarcode标记上设置一些名称空间。现在我记得为什么我非常讨厌SOAP :(