3。Ruby 和 SOAP
简单对象访问协议(SOAP)很快的成为了远程过程调用(RPC)的标准协议。(更多关于SOAP的信息可以分别参看http://www.linuxmagazine.com/2001-10/soap_04.html 和 http://www.linuxmagazine.com/2002-08/webs_01.html)
Ruby提供了对SOAP的强大支持,不管在客户端还是服务端来说都是这样的,使用SOAP4R,只需要4部分就能创建一个SOAP请求:
- 一个端点 (endpoint), 或者处理SOAP请求的网络地址,一个endpoint一般来说都是运行在WEB服务器环境中的代码,但是也有一些其它的SOAP传输,包括邮件。
- 一个命名空间(namespace), 定义了一个环境上下文,在这里解析调用的方法名。
- 一个方法名称。 远程过程调用的方法的名字。
- 一组参数。
使用SOAP4R的时候,我们需要在创建SOAP驱动的时候指定前两个参数,第三个参数则是为这个驱动绑定方法时候使用,最后的参数是调用实际需要的方法的时候使用。
比如,我们有一个处理销售订单的SOAP运行在http://my.server.com,我们要在客户端访问这个服务,先要创建一个 SOAP::Driver 对象,创建这个对象的时候需要指定命名空间和服务器地址(创建这个对象的方法的前两个参数和记录日志有关,这里我们可以不用考率)
一旦我们建立了这个驱动,就可以用它的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。
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。
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 |
发表于 @ 2004年12月06日 09:03:00|评论(loading...)