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 对象,创建这个对象的时候需要指定命名空间和服务器地址(创建这个对象的方法的前两个参数和记录日志有关,这里我们可以不用考率)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) endend这
个例子也要得益于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(" ") 910 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')1617 puts "Estimated result count: " + res.estimatedTotalResultsCount1819 res.resultElements.each do |entry|20 puts21 puts "#{entry.URL}: #{entry.title}"22 puts entry.snippet23 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 languageEstimated result count: 206000http://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 classclass Doubler def double(arg) arg + arg endend要在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)1011 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 wiki24wikiwiki$传
入参数为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 |