Ruby Rails 中使用 Savon 的 SOAP 调用在信封和主要操作周围变得奇怪

SOAP call in Ruby on Rails using Savon gets weird around the envelope and main operation

在使用 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 构建器也是如此)是 envelope 的属性和主要操作的 :generate_barcode 形状及其属性。我不明白为什么我在 GenerateBarcode.

之前得到前缀 wsdl:

我告诉 Savon 拿走我的 xml 并完全按照那样建造它,但它不起作用。按原样发送我的版本 returns 错误 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>

好的,这有效(已验证)

@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 从 GenerateBarcode 中删除 wsdl ans 属性在 GenerateBarcode 标签上设置了一些命名空间。现在我记得我为什么那么讨厌 SOAP :(