【问题标题】:Ruby Savon 2 gem: cannot specify XML child and sub-child elements to make valid request to SOAP API WebserviceRuby Savon 2 gem:无法指定 XML 子元素和子子元素以向 SOAP API Webservice 发出有效请求
【发布时间】:2015-06-18 08:57:02
【问题描述】:

已经进行了大量的谷歌搜索并查看了 Savon 2 文档,但我认为我没有在我的 ruby​​ 代码中正确指定 XML 子元素和子子元素,我需要对这个 SOAP 网络服务运行成功的请求.

在 main2.rb 中,我尝试使用方括号语法将文档从 BookReservationRequest 到 Booker 再到 UserWithoutALogin。 (这种方括号方法在响应方面的另一个示例中起作用)。不知何故,我没有在 Ruby 中正确指定这些,因为当我在 SOAP UI 中删除这些标签时,我在下面得到完全相同的错误消息。 (注意,我对 Ruby 还是很陌生!)

完整的错误跟踪:

ruby main2.rb
/Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/response.rb:85:in `raise_soap_and_http_errors!': (soap:Server) System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NullReferenceException: Object reference not set to an instance of an object. (Savon::SOAPFault)
   at Services.Internal.Helpers.CustomerHelper.GetCustomerIdFromGuestOrBookerType(Nullable`1 partnerServiceId, GuestOrBookerType guestOrBookerType) in c:\TeamCity\LB-QA-04\work\e2ec20c745b940f9\Source\Services\Internal\Helpers\CustomerHelper.cs:line 64
   at Services.Internal.Service.BookReservation(BookReservationRequest bookReservationRequest) in c:\TeamCity\LB-QA-04\work\e2ec20c745b940f9\Source\Services\Internal\Service.asmx.cs:line 289
   --- End of inner exception stack trace ---
    from /Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/response.rb:14:in `initialize'
    from /Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/operation.rb:72:in `new'
    from /Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/operation.rb:72:in `create_response'
    from /Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/operation.rb:58:in `call'
    from /Users/dan14/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/savon-2.11.1/lib/savon/client.rb:36:in `call'
    from main2.rb:11:in `core_info'
    from main2.rb:23:in `<main>'

Ruby 代码(main2.rb):

require 'savon'

class BookReservation

  def client
    client = Savon.client(wsdl: "http://some-example-soap-wsdl-link", follow_redirects: :follow_redirects)
  end

  def core_info(partner_code, restaurant_location_id, session_id, dining_date_and_time, size)
    message = { 'PartnerCode' => partner_code, 'RestaurantLocationId' => restaurant_location_id, 'SessionId' => session_id, 'DiningDateAndTime' => dining_date_and_time, 'Size' => size }
    response = client.call(:book_reservation, message: message)
    response.hash[:book_reservation_response]
  end

  def booker_info(first_name, last_name, email, guest_accepts_email_marketing)
    message = { 'FirstName' => first_name, 'LastName' => last_name, 'EMail' => email, 'GuestAcceptsEmailMarketingFromPartner' => guest_accepts_email_marketing }
    response = client.call([:book_reservation][:booker][:user_without_a_login], message: message)
    response.body[:book_reservation_response]
  end
end

  book = BookReservation.new
  puts book.core_info("DEV-DAN-BETH:73411", "10799", "DINNER", "2015-06-20T21:00:00", "2", )
  puts book.booker_info("John", "Smith", "john.smith@example.com", "true")

SoapUI 中的这个 xml 文档每次都返回一个有效/成功的响应:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://schemas.livebookings.net/OneFormat/Aggregator/Internal/1/0/">
    <soapenv:Header/>
    <soapenv:Body>      
        <ns:BookReservationRequest>            
            <ns:PartnerCode>DEV-DAN-BETH:73411</ns:PartnerCode>
            <ns:RestaurantLocationId>10799</ns:RestaurantLocationId>
            <ns:SessionId>DINNER</ns:SessionId>
            <ns:DiningDateAndTime>2015-06-20T21:00:00</ns:DiningDateAndTime>
            <ns:Size>2</ns:Size>
            <ns:Booker>
                <ns:UserWithoutALogin>
                    <ns:FirstName>John</ns:FirstName>
                    <ns:LastName>Smith</ns:LastName>
                    <ns:EMail>john.smith@example.com</ns:EMail>                      
                    <ns:GuestAcceptsEmailMarketingFromPartner>true</ns:GuestAcceptsEmailMarketingFromPartner>
               </ns:UserWithoutALogin>
            </ns:Booker>       
        </ns:BookReservationRequest>
    </soapenv:Body>
</soapenv:Envelope>

SoapUI 中的成功响应示例:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <BookReservationResponse xmlns="http://schemas.livebookings.net/OneFormat/Aggregator/Internal/1/0/">
         <ConfirmationNumber>T2NVGBUN</ConfirmationNumber>
         <ReservationId>34277666</ReservationId>
         <AllowedToCancelOnline>true</AllowedToCancelOnline>
      </BookReservationResponse>
   </soap:Body>
</soap:Envelope>

提前非常感谢!

【问题讨论】:

  • 我还尝试将方括号中的 booker 和 user_without_a_login 符号转换为原始的 xml 驼峰式字符串 - 即:['Booker']['UserWithoutALogin'] 但这也不起作用 -得到完全相同的错误信息!

标签: ruby xml soap soapui savon


【解决方案1】:

您的 SOAP 消息示例包含一个 Body,该 Body 包含一个 Book Reservation Request,其中包括一个 Booker 块。

但是,您的 BookReservation 类包含两个调用 Savon 客户端的方法 - 其中一个发送一个 BookReservationRequest - 但您从未在调度之前将 Booker 添加到消息哈希中。

几乎 100% 确定您的客户端正在发送无效的 SOAP 请求,因为您没有在 SOAP 正文中指定 &lt;ns:Booker&gt; 块。

我怀疑如果你更新你的类以包含一个如下所示的方法:

def execute(partner_code, restaurant_location_id, session_id, dining_date_and_time, size, first_name, last_name, email, guest_accepts_email_marketing)
    message = { 'PartnerCode' => partner_code, 'RestaurantLocationId' => restaurant_location_id, 'SessionId' => session_id, 'DiningDateAndTime' => dining_date_and_time, 'Size' => size }
    message.merge!('Booker' => { 'FirstName' => first_name, 'LastName' => last_name, 'EMail' => email, 'GuestAcceptsEmailMarketingFromPartner' => guest_accepts_email_marketing })

    response = client.call(:book_reservation, message: message)
    response.hash[:book_reservation_response]

结束

并用以下方式调用它:

book.execute(
  "DEV-DAN-BETH:73411", "10799", "DINNER", "2015-06-20T21:00:00", "2",
   "John", "Smith", "john.smith@example.com", "true" )

你会有更好的运气。

【讨论】:

  • 谢谢@macfinnigan 感觉我们快到了,我刚刚尝试了您的解决方案,但现在我遇到了一个新错误:System.ArgumentNullException: Value cannot be null. (Savon::SOAPFault) 当然我还需要在 Booker 中指定 'UserWithoutALogin' - 怎么做我在代码中这样做?
  • execute调用中的所有值也都需要是字符串吗? IE。也是“2”和“真”?
  • 我将其编辑为:message.merge!('Booker' =&gt; {'UserWithoutALogin' =&gt; { 'FirstName' =&gt; first_name, 'LastName' =&gt; last_name, 'EMail' =&gt; email, 'GuestAcceptsEmailMarketingFromPartner' =&gt; guest_accepts_email_marketing }}),运行时没有错误但没有打印数据。
  • 别担心,做了一些小的编辑,然后打印响应数据。谢谢!
  • 很高兴听到你到达那里。我总是使用将生成的 XML 转储到日志或控制台的方法,以便我可以看到为什么它与应有的不同。 XML 是个麻烦事。 :)
猜你喜欢
  • 2021-02-07
  • 1970-01-01
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
  • 2016-10-23
  • 2021-03-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多