我从1.1.0升级到Savon v2.0.2,它破坏了我的应用程序。我对代码进行了必要的调整,以解释错误回调(Savon::SOAP::Fault到Savon::SOAPFault, Savon::HTTP::Error到Savon::HTTPError等)中的变化,并使用#call vs #request方法。我在跟踪错误时遇到了麻烦,因为现在我得到了堆栈级别太深错误。我把我的上限增加到40000,但没有帮助。我不相信这是我的代码中的循环,因为在v2之前,代码工作得完美无缺。在Savon站点上提供的任何示例或Google搜索的结果都不能与我必须(并且已经)对服务于api的设备进行的XML调用相接近。这是我的客户端配置,XML结构,生成器和XML请求必须做的。我还将包括升级前工作版本中的代码。任何指导都将非常感激。为了安全起见,我模糊了IP、域名等。如果您需要更多的信息,请告诉我。
再次感谢您!
td两个版本通用:
@api = api.capitalize
service_api_host = '10.10.10.1'
url = "https://#{service_api_host}:8443/#{api}/#{api}?wsdl"
@uname = 'username'
@pwd = 'password'
@xml1 = "xmlns:soapenv"
@xml2 = "xmlns:ws"
@xmlns1 = "http://schemas.xmlsoap.org/soap/envelope/"
@xmlns2 = "http://ws.#{@api.downcase}.myappliances_domain.com"
典型XML请求:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.reportingservices.myappliances_domain.com">
<soapenv:Header xmlns:svsec="http://services.myappliances_domain.com">
<svsec:username>username</svsec:username>
<svsec:password>password</svsec:password>
</soapenv:Header>
<soapenv:Body>
<ws:RunTimeSeriesReportRequest>
<ReportDefinition>MyReportDefinition</ReportDefinition>
<CsvAttachmentFormat>
<Compression>None</Compression>
<Encoding>UTF-8</Encoding>
<Headers>true</Headers>
</CsvAttachmentFormat>
<TimeSeriesReportQuery>
<QueryFields>
<QueryField>PeriodStart</QueryField>
<QueryField>PeriodEnd</QueryField>
<QueryField>Subscriber.Name</QueryField>
<QueryField>TotalReceivedBytes</QueryField>
<QueryField>TotalTransmittedBytes</QueryField>
<QueryField>TotalBytes</QueryField>
</QueryFields>
<QueryFilters>
<QueryFilter>
<QueryField>Subscriber.Name</QueryField>
<Criteria>Equal</Criteria>
<Value>078DF7</Value>
</QueryFilter>
</QueryFilters>
<MaxRows>0</MaxRows>
<QueryLocalDataHomeOnly>false</QueryLocalDataHomeOnly>
<TimeSeries>
<Start>2012-12-19T06:00:00-07:00</Start>
<End>2012-12-20T00:00:00-07:00</End>
<TimeZone>America/Phoenix</TimeZone>
<Interval>
<Unit>Hours</Unit>
<Value>18</Value>
</Interval>
</TimeSeries>
</TimeSeriesReportQuery>
</ws:RunTimeSeriesReportRequest>
</soapenv:Body>
</soapenv:Envelope>
为了完整:(创建唯一请求的构建器之一)
xml = Builder::XmlMarkup.new( :indent=>2 )
xml.soapenv:Envelope, :"#{@xml1}"=>"#{@xmlns1}", :"#{@xml2}"=>"#{@xmlns2}" do
xml.tag!( 'soapenv:Header', :'xmlns:svsec' => 'http://services.myappliances_domain.com' ) do
xml.tag!( 'svsec:username', @uname )
xml.tag!( 'svsec:password', @pwd )
end
xml.tag!( 'soapenv:Body' ) do
xml.tag!( "ws:#{request}" ) do
xml.ReportDefinition('MyReportDefinition')
xml.CsvAttachmentFormat do
xml.Compression('None')
xml.Encoding('UTF-8')
xml.Headers('true')
end
xml.TimeSeriesReportQuery do
xml.QueryFields do
xml.QueryField('PeriodStart')
xml.QueryField('PeriodEnd')
xml.QueryField('Subscriber.Name')
xml.QueryField('TotalReceivedBytes')
xml.QueryField('TotalTransmittedBytes')
xml.QueryField('TotalBytes')
end
xml.QueryFilters do
xml.QueryFilter do
xml.QueryField('Subscriber.Name')
xml.Criteria('Equal')
xml.Value(sub)
end
end
xml.MaxRows(0)
xml.QueryLocalDataHomeOnly('false')
xml.TimeSeries do
xml.Start("#{start_date}")
xml.End("#{end_date}")
xml.TimeZone('America/Phoenix')
xml.Interval do
xml.Unit('Hours')
xml.Value('18')
end
end
end
end
end
end
升级前:
客户机def @client = Savon::Client.new do |wsdl, http|
wsdl.document = url
http.auth.ssl.verify_mode = :none
http.read_timeout = 120
end
请求调用
@response = @client.request "#{params[:reqMethod]}" do
soap.xml = "#{params[:xml]}"
end
升级后:
客户机def@client = Savon.client(wsdl: url,
encoding: "UTF-8",
soap_version: 2,
ssl_verify_mode: :none,
open_timeout: 5,
read_timeout: 120)
请求调用
response = @client.call(:"#{params[:reqMethod]}", xml: params[:xml])
下面是返回Builder结果的典型方法。它是一个字符串,不是一个对象。
从rails控制台:
ruby-1.9.3-p0 :020 > @uname = 'username'
=> "username"
ruby-1.9.3-p0 :021 > @pwd = 'password'
=> "password"
ruby-1.9.3-p0 :022 > api = 'SubscriberServices'
=> "SubscriberServices"
ruby-1.9.3-p0 :023 > @api = api.capitalize
=> "Subscriberservices"
ruby-1.9.3-p0 :024 > @xml1 = "xmlns:soapenv"
=> "xmlns:soapenv"
ruby-1.9.3-p0 :025 > @xml2 = "xmlns:ws"
=> "xmlns:ws"
ruby-1.9.3-p0 :026 > @xmlns1 = "http://schemas.xmlsoap.org/soap/envelope/"
=> "http://schemas.xmlsoap.org/soap/envelope/"
ruby-1.9.3-p0 :027 > @xmlns2 = "http://ws.#{@api.downcase}.myappliance_domain.com"
=> "http://ws.subscriberservices.myappliance_domain.com"
ruby-1.9.3-p0 :028 > def getSubAttributes(subscriber)
ruby-1.9.3-p0 :029?> request = 'LookupSubscriberRequest'
ruby-1.9.3-p0 :030?>
ruby-1.9.3-p0 :031 > xml = Builder::XmlMarkup.new( :indent=>2 )
ruby-1.9.3-p0 :032?> xml.soapenv:Envelope, :"#{@xml1}"=>"#{@xmlns1}", :"#{@xml2}"=>"#{@xmlns2}" do
ruby-1.9.3-p0 :033 > xml.tag!( 'soapenv:Header', :'xmlns:svsec' => 'http://services.myappliance_domain.com' ) do
ruby-1.9.3-p0 :034 > xml.tag!( 'svsec:username', @uname )
ruby-1.9.3-p0 :035?> xml.tag!( 'svsec:password', @pwd )
ruby-1.9.3-p0 :036?> end
ruby-1.9.3-p0 :037?> xml.tag!( 'soapenv:Body' ) do
ruby-1.9.3-p0 :038 > xml.tag!( "ws:#{request}" ) do
ruby-1.9.3-p0 :039 > xml.SubscriberKey() do
ruby-1.9.3-p0 :040 > xml.SubscriberRealmKey() do
ruby-1.9.3-p0 :041 > xml.Name('DEFAULT')
ruby-1.9.3-p0 :042?> end
ruby-1.9.3-p0 :043?> xml.Name(subscriber)
ruby-1.9.3-p0 :044?> end
ruby-1.9.3-p0 :045?> xml.ResponseGroups() do
ruby-1.9.3-p0 :046 > xml.ResponseGroup('Subscriber.Attributes')
ruby-1.9.3-p0 :047?> xml.ResponseGroup('Subscriber.CurrentIpAssignments')
ruby-1.9.3-p0 :048?> end
ruby-1.9.3-p0 :049?> end
ruby-1.9.3-p0 :050?> end
ruby-1.9.3-p0 :051?> end
ruby-1.9.3-p0 :052?> end
=> nil
ruby-1.9.3-p0 :053 > x = getSubAttributes('3C754A70BDE3')
=> "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.subscriberservices.myappliance_domain.com">n <soapenv:Header xmlns:svsec="http://services.myappliance_domain.com">n <svsec:username>username</svsec:username>n <svsec:password>password</svsec:password>n </soapenv:Header>n <soapenv:Body>n <ws:LookupSubscriberRequest>n <SubscriberKey>n <SubscriberRealmKey>n <Name>DEFAULT</Name>n </SubscriberRealmKey>n <Name>3C754A70BDE3</Name>n </SubscriberKey>n <ResponseGroups>n <ResponseGroup>Subscriber.Attributes</ResponseGroup>n <ResponseGroup>Subscriber.CurrentIpAssignments</ResponseGroup>n </ResponseGroups>n </ws:LookupSubscriberRequest>n </soapenv:Body>n</soapenv:Envelope>n"
ruby-1.9.3-p0 :054 > x.class
=> String
ruby-1.9.3-p0 :055 > x.target!
NoMethodError: undefined method `target!' for #<String:0x0000000497a348>
from (irb):55
from /usr/local/rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.9/lib/rails/commands/console.rb:47:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.9/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p0/gems/railties-3.2.9/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
ruby-1.9.3-p0 :056 >
更新2
如果我不显式返回xml Builder对象,我得到一个字符串。
api = 'SubscriberServices'
@api = api.capitalize
@uname = 'username'
@pwd = 'password'
@xml1 = "xmlns:soapenv"
@xml2 = "xmlns:ws"
@xmlns1 = "http://schemas.xmlsoap.org/soap/envelope/"
@xmlns2 = "http://ws.#{@api.downcase}.myappliance_domain.com"
def getSubAttributes(subscriber)
request = 'LookupSubscriberRequest'
xml = Builder::XmlMarkup.new( :indent=>2 )
xml.soapenv:Envelope, :"#{@xml1}"=>"#{@xmlns1}", :"#{@xml2}"=>"#{@xmlns2}" do
xml.tag!( 'soapenv:Header', :'xmlns:svsec' => 'http://services.myappliance_domain.com' ) do
xml.tag!( 'svsec:username', @uname )
xml.tag!( 'svsec:password', @pwd )
end
xml.tag!( 'soapenv:Body' ) do
xml.tag!( "ws:#{request}" ) do
xml.SubscriberKey() do
xml.SubscriberRealmKey() do
xml.Name('DEFAULT')
end
xml.Name(subscriber)
end
xml.ResponseGroups() do
xml.ResponseGroup('Subscriber.Attributes')
xml.ResponseGroup('Subscriber.CurrentIpAssignments')
end
end
end
end
return xml
end
测试……
ruby-1.9.3-p0 :294 > api = 'SubscriberServices'
=> "SubscriberServices"
ruby-1.9.3-p0 :295 > @api = api.capitalize
=> "Subscriberservices"
ruby-1.9.3-p0 :296 > @uname = 'username'
=> "username"
ruby-1.9.3-p0 :297 > @pwd = 'password'
=> "password"
ruby-1.9.3-p0 :298 >
ruby-1.9.3-p0 :299 > @xml1 = "xmlns:soapenv"
=> "xmlns:soapenv"
ruby-1.9.3-p0 :300 > @xml2 = "xmlns:ws"
=> "xmlns:ws"
ruby-1.9.3-p0 :301 > @xmlns1 = "http://schemas.xmlsoap.org/soap/envelope/"
=> "http://schemas.xmlsoap.org/soap/envelope/"
ruby-1.9.3-p0 :302 > @xmlns2 = "http://ws.#{@api.downcase}.myappliance_domain.com"
=> "http://ws.subscriberservices.myappliance_domain.com"
ruby-1.9.3-p0 :303 >
ruby-1.9.3-p0 :304 > def getSubAttributes(subscriber)
ruby-1.9.3-p0 :305?> request = 'LookupSubscriberRequest'
ruby-1.9.3-p0 :306?>
ruby-1.9.3-p0 :307 > xml = Builder::XmlMarkup.new( :indent=>2 )
ruby-1.9.3-p0 :308?> xml.soapenv:Envelope, :"#{@xml1}"=>"#{@xmlns1}", :"#{@xml2}"=>"#{@xmlns2}" do
ruby-1.9.3-p0 :309 > xml.tag!( 'soapenv:Header', :'xmlns:svsec' => 'http://services.myappliance_domain.com' ) do
ruby-1.9.3-p0 :310 > xml.tag!( 'svsec:username', @uname )
ruby-1.9.3-p0 :311?> xml.tag!( 'svsec:password', @pwd )
ruby-1.9.3-p0 :312?> end
ruby-1.9.3-p0 :313?> xml.tag!( 'soapenv:Body' ) do
ruby-1.9.3-p0 :314 > xml.tag!( "ws:#{request}" ) do
ruby-1.9.3-p0 :315 > xml.SubscriberKey() do
ruby-1.9.3-p0 :316 > xml.SubscriberRealmKey() do
ruby-1.9.3-p0 :317 > xml.Name('DEFAULT')
ruby-1.9.3-p0 :318?> end
ruby-1.9.3-p0 :319?> xml.Name(subscriber)
ruby-1.9.3-p0 :320?> end
ruby-1.9.3-p0 :321?> xml.ResponseGroups() do
ruby-1.9.3-p0 :322 > xml.ResponseGroup('Subscriber.Attributes')
ruby-1.9.3-p0 :323?> xml.ResponseGroup('Subscriber.CurrentIpAssignments')
ruby-1.9.3-p0 :324?> end
ruby-1.9.3-p0 :325?> end
ruby-1.9.3-p0 :326?> end
ruby-1.9.3-p0 :327?> end
ruby-1.9.3-p0 :328?>
Display all 540 possibilities? (y or n)
ruby-1.9.3-p0 :328?> xml
ruby-1.9.3-p0 :329?> end
=> nil
ruby-1.9.3-p0 :330 > x = getSubAttributes('3C754A70BDE3')
=> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.subscriberservices.myappliance_domain.com">
<soapenv:Header xmlns:svsec="http://services.myappliance_domain.com">
<svsec:username>username</svsec:username>
<svsec:password>password</svsec:password>
</soapenv:Header>
<soapenv:Body>
<ws:LookupSubscriberRequest>
<SubscriberKey>
<SubscriberRealmKey>
<Name>DEFAULT</Name>
</SubscriberRealmKey>
<Name>3C754A70BDE3</Name>
</SubscriberKey>
<ResponseGroups>
<ResponseGroup>Subscriber.Attributes</ResponseGroup>
<ResponseGroup>Subscriber.CurrentIpAssignments</ResponseGroup>
</ResponseGroups>
</ws:LookupSubscriberRequest>
</soapenv:Body>
</soapenv:Envelope>
<inspect/>
ruby-1.9.3-p0 :331 > x.class
=> "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.subscriberservices.myappliance_domain.com">n <soapenv:Header xmlns:svsec="http://services.myappliance_domain.com">n <svsec:username>username</svsec:username>n <svsec:password>password</svsec:password>n </soapenv:Header>n <soapenv:Body>n <ws:LookupSubscriberRequest>n <SubscriberKey>n <SubscriberRealmKey>n <Name>DEFAULT</Name>n </SubscriberRealmKey>n <Name>3C754A70BDE3</Name>n </SubscriberKey>n <ResponseGroups>n <ResponseGroup>Subscriber.Attributes</ResponseGroup>n <ResponseGroup>Subscriber.CurrentIpAssignments</ResponseGroup>n </ResponseGroups>n </ws:LookupSubscriberRequest>n </soapenv:Body>n</soapenv:Envelope>n<inspect/>n<class/>n"
ruby-1.9.3-p0 :332 > s = x.to_xml
=> "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.subscriberservices.myappliance_domain.com">n <soapenv:Header xmlns:svsec="http://services.myappliance_domain.com">n <svsec:username>username</svsec:username>n <svsec:password>password</svsec:password>n </soapenv:Header>n <soapenv:Body>n <ws:LookupSubscriberRequest>n <SubscriberKey>n <SubscriberRealmKey>n <Name>DEFAULT</Name>n </SubscriberRealmKey>n <Name>3C754A70BDE3</Name>n </SubscriberKey>n <ResponseGroups>n <ResponseGroup>Subscriber.Attributes</ResponseGroup>n <ResponseGroup>Subscriber.CurrentIpAssignments</ResponseGroup>n </ResponseGroups>n </ws:LookupSubscriberRequest>n </soapenv:Body>n</soapenv:Envelope>n<inspect/>n<class/>n<to_xml/>n"
ruby-1.9.3-p0 :333 > s.class
=> String
ruby-1.9.3-p0 :334 >
我不能完全看到xml
对象(来自Builder::XmlMarkup.new
)和params[:xml]
之间的关系,但我有一个堆栈级别太深的问题,并通过使用message: xml.target!
修复了这个问题。