Ruby中的SOAP编程

3。Ruby 和 SOAP

简单对象访问协议(SOAP)很快的成为了远程过程调用(RPC)的标准协议。(更多关于SOAP的信息可以分别参看http://www.linuxmagazine.com/2001-10/soap_04.htmlhttp://www.linuxmagazine.com/2002-08/webs_01.html)

Ruby提供了对SOAP的强大支持,不管在客户端还是服务端来说都是这样的,使用SOAP4R,只需要4部分就能创建一个SOAP请求:

  1. 一个端点 (endpoint), 或者处理SOAP请求的网络地址,一个endpoint一般来说都是运行在WEB服务器环境中的代码,但是也有一些其它的SOAP传输,包括邮件。
  2. 一个命名空间(namespace), 定义了一个环境上下文,在这里解析调用的方法名。
  3. 一个方法名称。 远程过程调用的方法的名字。
  4. 一组参数。

使用SOAP4R的时候,我们需要在创建SOAP驱动的时候指定前两个参数,第三个参数则是为这个驱动绑定方法时候使用,最后的参数是调用实际需要的方法的时候使用。

 

比如,我们有一个处理销售订单的SOAP运行在http://my.server.com,我们要在客户端访问这个服务,先要创建一个 SOAP::Driver 对象,创建这个对象的时候需要指定命名空间和服务器地址(创建这个对象的方法的前两个参数和记录日志有关,这里我们可以不用考率)

NS  = "urn:ordersService"
SVR = "http://my.server.com/orders"
drv = SOAP::Driver.new(nil, nil, NS, SVR)

一旦我们建立了这个驱动,就可以用它的addMethod方法增加我们需要向服务器调用的方法的名称,第一个参数是这个方法的名称,其余的参数是这个方法需要的参数名,这里,我们需要访问的方法名为orders_for_product(译者注:此处是否应该是orders_for?),传给它的参数十客户帐号和产品代码。(Ruby不用WSDL描述SOAP接口)

 

drv.addMethod("orders_for", "cust_acct","prod_code")

一旦所有的东西都完成,我们可以用这个方法任意次数的向服务器调用:

customers.each do |cust_acct|
  products.each do |prod_code|
    orders = drv.orders_for(cust_acct, prod_code)
    process(orders)
  end
end

这个例子也要得益于Ruby语言的动态性,比如orders_for方法动态的加到了SOAP驱动对象,所以我们可以用drv.orders_for来调用这个方法。而且我们也不需要定义这个方法的返回值的形式,SOAP驱动会自动将从服务器得到的结果转换为适当地Ruby对象。

为了更详细的说明一下,我们来看一个真正的例子。清单4显示了如何用SOAP从googel搜索引擎取得查询结果,这段代码基于Ian Macdonald的google.rb。运行这个程序之前,你需要在google 上注册一下 (http://www.google.com/accounts) ,然后取得一个key,在第三行指定你得到的key。

 

 

清单4: 使用SOAP查询google

 1   require "soap/driver"
 2   ENDPOINT = 'http://api.google.com/search/beta2'
 3   NS = 'urn:GoogleSearch'
 4   KEY = "get_a_key_from_google"
 5
 6   fail "Missing query args" if ARGV.empty?
 7
 8   query = ARGV.join(" ")
 9
10   soap = SOAP::Driver.new(nil, nil, NS, ENDPOINT)
11   soap.addMethodWithSOAPAction(
12     'doGoogleSearch', NS, 'key', 'q', 'start', 'maxResults', 
13       'filter','restrict', 'safeSearch', 'lr', 'ie', 'oe')
14   res = soap.doGoogleSearch(
15     KEY, query, 0, 10, false, nil, false, nil, 'latin1', 'latin1')
16
17   puts "Estimated result count: " + res.estimatedTotalResultsCount
18
19   res.resultElements.each do |entry|
20     puts
21     puts "#{entry.URL}: #{entry.title}"
22     puts entry.snippet
23   end

实际的google查询是在google的服务器上由方法doGoogleSearch执行的,这个方法接收10个参数(关于这10个参数的具体意义,可以参考google的web API文档),但是我们的例子里,我们只是指定了查询条件,其它参数我们都使用了默认值。在第11行,我们给SOAP驱动增加了方法doGoogleSearch,第14行我们调用这个方法,执行真正的查询。

从google返回的结果是很复杂的对象,从高层来看,这个结果包括这个查询本身的一些信息,比如开始和结束的索引值,查询用到的条件,查询消耗的时间等。查询结果存在一个数组里面。这和你手工在google页面上查询看到的编号的结果一样。每条查询结果记录本身也是很复杂的对象,在我们的例子里,我们只取出了它的标题,url,和一部分文本。

 

SOAP接口把我们的工作变得很简单,它自动创建对结果对象的迭代,创建返回结果对象的各种属性的访问方法,然后,我们可以简单的使用:

res.resultElements.each do |element|
  ...
end

如果你在命令提示符下运行清单4的程序,查询参数为"ruby soap",结果如下:

 

$ ruby google_search.rb ruby language
Estimated result count: 206000
http://www.ruby-lang.org/en/: <b>Ruby</b> Home Page
  <b>...</b> Japanese Page If you can read this oriental 
<b>language</b>, <br> you can get more information about <b>Ruby</b>.
Site <b>...</b> http://slashdot.org/developers/01/08/11/2211254.shtml: Slashdot
| Progra.... <b>...</b> Programming in the <b>Ruby</b> <b>Language</b>.
<b>...</b> This discussion has<br> been archived. No new comments
can be posted. http://dev.rubycentral.com/faq/rubyfaq.html: The
<b>Ruby Language</b> FAQ The <b>Ruby</b> <b>Language</b> FAQ. Originally by:
Shugo Maeda.<br> Now maintained by Dave Thomas with help
from Andy Hunt. <b>...</b>

(注:此表为译者折行之后的结果,原来的内容可能超出宽度,影响阅读)

在Ruby中编写一个SOAP服务器端也是非常简单的。你所需要做的就是需要发布的接口对象,然后把这些对象发布的SOAP服务器的servlet上。你所编写的对象不需要知道SOAP的任何什么东西。比如,清单5表示的是一个简单的类,有一个简单的方法double,接收一个参数,返回两个这个参数相加的结果。

清单5: The file doubler.rb, the Ruby SOAP doubling class

class Doubler
  def double(arg)
    arg + arg
  end
end

要在SOAP服务器中访问这个方法,我们需要把它组装到SOAP服务器的命名空间上。在Ruby中,最简单的方法是使用web服务器工具箱WEBRick。结合soaplet.rb这个servlet代码(在SOAP4R包的samples/webrick目录下),我们可以用很少的一些代码来实现一个完整的SOAP服务器,代码见清单6。

 

清单6: A Ruby SOAP server

 1   require 'webrick'
 2   require 'soaplet'
 3   require 'doubler'
 4
 5   server = WEBrick::HTTPServer.new(:Port => 2001)
 6
 7   soaplet = SOAP::WEBrickSOAPlet.new
 8   soaplet.addServant('urn:doublerService', Doubler.new)
 9   server.mount("/doubler", soaplet)
10
11   trap("INT") { server.shutdown }
12   server.start

前三行只是简单的引入了需要的库,soaplet,Double类等。第5行是创建一个web server必须得步骤(本例端口为2001),第7行创建了一个soaplet(一个把SOAP请求发送到一个对象的servlet)。第8行把这个servlet帮定到一个Doubler对象,第9行将这个soaplet映射到web server的/doubler。第12行启动了服务器进程序,但是第11行干什么用呢?当你启动一个WEBRick服务时,这个服务器程序将处理请求,返回结果,但是,我们想我们的服务器程序能完整的关闭,第11行就是为了完成这种功能,这一行给server注册了一个处理SIGINT信号的处理器,当收到这样的信号时,调用server的shutdown方法,在大多数操作系统下,control-c将产生SIGINT信号,所以,我们可以在命令提示符下控制我们的web 服务器。

我们可以用下面清单7中的SOAP客户端程序来测试一下服务器端。第10行还展示了rescue的另一个特点:这个语句首先尝试将参数(传过来的时候为字符串)转换为整型,如果转换失败,则rescue将会捕捉这个异常,并且返回原来的参数。这样的结果是double方法能接收的参数可以是整型的和字符串型的,让我们看看客户端运行的时候会有什么不同。

$ ruby soap_client.rb 12 wiki
24
wikiwiki
$

传入参数为12,我们得到的结果为24,当我们传入字符串wiki的时候,我们得到的是wikiwiki。Ruby中类型的多态性也传播到了SOAP接口。因为double方法是arg+arg,所以如果参数为整型,返回两个数相加的结果,如果参数为字符串,则返回两个字符串连接的结果。

 

清单7: The doubler SOAP client

 1   require "soap/driver"
 2
 3   SVR = 'http://localhost:2001/doubler'
 4   NS  = 'urn:doublerService'
 5
 6   soap = SOAP::Driver.new(nil, nil, NS, SVR)
 7   soap.addMethod('double', 'arg')
 8
 9   ARGV.each do |arg|
10     arg = (Integer(arg) rescue arg)
11     puts soap.double(arg)
12   end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值