savon-ruby-gem中的每个请求的命名空间



我需要发送一个请求,如:

<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>

为了做到这一点,我可以绕过萨冯。

现在我的理解是Savon正在查看WSDL,以确定要添加的命名空间。有一个叫做element_form_default的东西,它与namespace_identifiercallsoap_header的手动补丁结合起来稍微做了我想要的事情,例如

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>

为了回答我自己的问题,我认为savon不能跟进名称空间。然而,在深入研究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是一个基于xml.erb文件返回字符串SOAP信封的方法。例如

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操作也是如此。

我并不是说这是最好的方法,但它通过在本地传递名称空间,让我的生活更轻松。

最新更新