По запросу пространства имен в Савон Рубин Gem - PullRequest
0 голосов
/ 04 декабря 2018

Мне нужно отправить запрос вроде:

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://tempuri.org/" xmlns:ns2="http://www.w3.org/2005/08/addressing">
   <env:Header>
      <ns2:Action>http://tempuri.org/IDataImportService/Login</ns2:Action>
      <ns2:To>https://URLHERE.svc</ns2:To>
   </env:Header>
   <env:Body>
      <ns1:Login>
         <ns1:userName>USERNAME</ns1:userName>
         <ns1:password>PASSWORD</ns1:password>
      </ns1:Login>
   </env:Body>
</env:Envelope>

Для этого я могу взломать Савон.

Теперь я понимаю, что Савон смотрит на WSDL, чтобы выяснить, какое пространство имендобавить.Есть вещь под названием element_form_default , которая немного выполняет то, что я хочу, в сочетании с namespace_identifier и ручным патчем soap_header в call Например

client = Savon.client(
  wsdl: 'https://urlhere.svc?wsdl',
  log: true,
  soap_version: 2,
  pretty_print_xml: true,
  log_level: :debug,
  namespaces: {
    'xmlns:ns1' => 'http://tempuri.org/',
    'xmlns:ns2' => 'http://www.w3.org/2005/08/addressing'
  },
  namespace_identifier: 'ns1',
  element_form_default: :qualified
)

client.call(
  :login,
  message: {
    'userName' => USERNAME,
    'password' => PASSWORD,
  },
  soap_header: {
    'ns2:Action' => 'http://tempuri.org/IDataImportService/Login',
    'ns2:To' => 'https://urlhere.svc'
  }
)

Я оставлю этонапример, если мне не нужно было делать еще один запрос с 3 различными пространствами имен и передавать контекст входа в систему ...

У меня есть следующие вопросы:

  1. Есть ли способчтобы избежать ручного исправления этих пространств имен?
  2. Почему он работает правильно в php со службами SOAP?

Например, что мне нужно сделать в следующем запросе:

<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://schemas.datacontract.org/2004/07/Common.DataContracts" xmlns:ns2="http://tempuri.org/" xmlns:ns3="http://www.w3.org/2005/08/addressing" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <env:Header>
      <ns3:Action>http://tempuri.org/IDataImportService/CreateLead</ns3:Action>
      <ns3:To>https://URLHERE.svc</ns3:To>
   </env:Header>
   <env:Body>
      <ns2:CreateLead>
         <ns2:autoItContext>
            <ns1:AddressNamePrimary xsi:nil="true" />
            <ns1:Addresshousenumber xsi:nil="true" />
            <ns1:Addressstreet xsi:nil="true" />
         </ns2:autoItContext>
         <ns2:companyId>111</ns2:companyId>
         <ns2:description></ns2:description>
         <ns2:leadData>
            <ns1:C_Address xsi:nil="true" />
            <ns1:C_Address2 xsi:nil="true" />
            <ns1:C_CellPhoneNumber xsi:nil="true" />
            <ns1:C_City xsi:nil="true" />
            <ns1:C_CprNumber1 xsi:nil="true" />
            <ns1:C_CvrNumber xsi:nil="true" />
            <ns1:C_Email>email@email.com</ns1:C_Email>
         </ns2:leadData>
         <ns2:checkForDuplicates>false</ns2:checkForDuplicates>
         <ns2:listId xsi:nil="true" />
      </ns2:CreateLead>
   </env:Body>
</env:Envelope>

1 Ответ

0 голосов
/ 17 декабря 2018

Чтобы ответить на мой собственный вопрос, я не думаю, что savon может отслеживать пространства имен.Однако, покопавшись в коде Савона, я понял, что могу решить эту проблему, поскольку запросы SOAP не столь важны для моего приложения.

Вот хорошее решение для работы с несколькими пространствами имен:

  def login_request
    request = Savon::SOAPRequest.new(globals).build(
      soap_action: :login,
      cookies: locals[:cookies],
      headers: locals[:headers]
    )
    request.headers['Content-Type'] = 'application/soap+xml'
    request.url = @url
    request.body = login_xml_string
    HTTPI.post(request)
  end


  def globals
    @_globals ||= Savon::GlobalOptions.new
  end

  def locals
    @_locals ||= Savon::LocalOptions.new
  end

Где login_xml_string - это метод, возвращающий конвертируемый SOAP конверт на основе файла xml.erb.Например,

def login_xml_string
  @view_paths.render(file: 'app/views/path/to/file/login.xml.erb',
    locals: { user_name: @username, password: @password, url: @url}
  ).gsub(/\n[\s+]{0,}/, '')
end

И @view_paths установлены на ActionView::Base.new(ActionController::Base.view_paths, {})

То же самое касается остальных действий SOAP, которые мне нужно вызвать.

Я не говорюэто лучший подход, но он облегчил мне жизнь с пространствами имен, передав их местным жителям.

...