Ruby 和 Web
编写 CGI 脚本
你可以用Ruby轻松的编写CGI脚本,为了让Ruby脚本产生HTML输出,你只需要这样做:
#!/usr/bin/env ruby print "HTTP/1.0 200 OK\r\n" print "Content-type: text/html\r\n\r\n" print "<html><body>Hello World!</body></html>\r\n"
你可以用Ruby的正则表达式来解析输入字符串,查询环境变量,检查标记,填充模板,转义(escape )特殊字符,格式化HTML,然后输出。
或者,你可以用类CGI。
使用cgi.rb
类CGI主要来帮助你更方便的编写CGI脚本,使用它,你可以操纵表单(form),cookies和环境变量,维护有状态的session等等。关于它的文档在第497页,但是我们在这里要先看一下它大体的功能。
引用(Quoting)
当处理URL和HTML的时候,我们必须注意对一些特殊字符的引用。比如,一个斜线 (``/'') 在URL里有特殊意义,如果它不是URL的路径名称的一部分,那么它必须被转义(escaped)。也就是说,它在URL中将被转换为 ``%2F
'',而且反过来你要想使用它,必须把它再转换为斜线。空格和and符号("&")也是特殊字符。为了处理这样的情况,CGI提供了方法CGI.escape
和CGI.unescape
。
require 'cgi' puts CGI.escape( "Nicholas Payton/Trumpet & Flugel Horn" )结果:
Nicholas+Payton%2FTrumpet+%26+Flugel+Horn
类似的,你也许需要对HTML中的特殊字符进行转义(escape ):
require 'cgi' puts CGI.escapeHTML( '<a href="/mp3">Click Here</a>' )结果:
<a href="/mp3">Click Here</a>
而且,你也可以只对HTML的一部分标记进行转义,而不是全部:
require 'cgi' puts CGI.escapeElement('<hr><a href="/mp3">Click Here</a><br>','A')produces:
<hr><a href="/mp3">Click Here</a><br>
这里又有A标记被转义了,其它标记都没有变化。
每个这样的转义方法都有一个un-开头的版本,来恢复这个转义之前的字符串。
表单(Forms)
使用CGI类你有两种方法访问HTML传过来的参数。比如我们有一个URL/cgi-bin/lookup?player=Miles%20Davis&year=1958
,你可以用CGI#[ ]方法直接访问player和year变量:
require 'cgi'
cgi = CGI.new
cgi['player']
?["Miles Davis"]
cgi['year']
?["1958"]
或者,你可以把所有参数放入一个Hash中,再从这个哈希查询参数。
require 'cgi'
cgi = CGI.new
h = cgi.params
h['player']
?["Miles Davis"]
创建窗体(Forms)和 HTML
CGI类包含了很多产生HTML的方法,每个HTML标记都有一个方法。为了使用这些方法,你首先要创建一个CGI对象,这可以通过CGI.new
方法。这个方法可以接收一个参数表示HTML的级别。比如,我们这里用了html3。
为了使得这些标记嵌套方便,这些方法都接受一个block作为来处理内容,这个block返回一个字符串,这也是这个tag的内容。比如下面的例子,我们加入了一些换行是为了能适应屏幕,能使得它被很好的显示而已。
require "cgi" cgi = CGI.new("html3") # add HTML generation methods cgi.out{ cgi.html{ cgi.head{ "\n"+cgi.title{"This Is a Test"} } + cgi.body{ "\n"+ cgi.form{"\n"+ cgi.hr + cgi.h1 { "A Form: " } + "\n"+ cgi.textarea("get_text") +"\n"+ cgi.br + cgi.submit } } } }produces:
Content-Type: text/html Content-Length: 302 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><HEAD> <TITLE>This Is a Test</TITLE></HEAD><BODY> <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded"> <HR><H1>A Form: </H1> <TEXTAREA NAME="get_text" ROWS="10" COLS="70"></TEXTAREA> <BR><INPUT TYPE="submit"></FORM></BODY></HTML>
这段代码将产生一个HTML文档,主题(title)为“This Is a Test”,然后一个水平线,然后是一个header,一个测试的输入框,一个提交按钮。当接收到这个提交的页面,你会得到一个变量名为get_text,其值为你输入的文本。
Cookies
你可以通过使用cookies在客户机上存放各种有用的信息,你可以创建一个有名字的cookie,并且设定一个指定的值。为了将这个cookie发送到浏览器,你需要在CGI#out中设置cookie 头(header)。
require "cgi" cookie = CGI::Cookie.new("rubyweb", "CustID=123", "Part=ABC"); cgi = CGI.new("html3") cgi.out( "cookie" => [cookie] ){ cgi.html{ "\nHTML content here" } }produces:
Content-Type: text/html Content-Length: 86 Set-Cookie: rubyweb=CustID%3D123&Part%3DABC; path= <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML> HTML content here</HTML>
当用户下次访问这个页面时,你可以取得cookieCustID
和Part
,然后将它们显示在HTML输出中。
require "cgi" cgi = CGI.new("html3") cgi.out{ cgi.html{ cgi.pre{ cookie = cgi.cookies["rubyweb"] "\nCookies are\n" + cookie.value.join("\n") } } }produces:
Content-Type: text/html Content-Length: 111 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML><PRE> Cookies are CustID=123 Part=ABC</PRE></HTML>
Sessions
cookies需要我们进行一些人为处理后才变得有用,我们真正需要的是一个session:web客户端的持久性的状态。session在Ruby中用CGI::Session
处理,它也使用了cookie,但是提供了一个高层次的接口。
require "cgi" require "cgi/session" cgi = CGI.new("html3") sess = CGI::Session.new( cgi, "session_key" => "rubyweb", "session_id" => "9650", "new_session" => true, "prefix" => "web-session.") sess["CustID"] = 123 sess["Part"] = "ABC" cgi.out{ cgi.html{ "\nHTML content here" } }
这将给用户rubyweb发送一个cookie,它的值为9650。它也会在服务器的上建立一个文件$TMP/web-session.9650
,以“键-值”(key-value)的方式保存着CustID和Part的值。
当这个用户又访问这个网站时,你需要一个参数指明session id。在这个例子里应该是rubyweb=9650
,然后,你就可以取得所有和这个sesion相关的数据了。
require "cgi" require "cgi/session" cgi = CGI.new("html3") sess = CGI::Session.new( cgi, "session_key" => "rubyweb", "prefix" => "web-session.") cgi.out{ cgi.html{ "\nCustomer #{sess['CustID']} orders an #{sess['Part']}" } }
将Ruby嵌入HTML
到目前为止我们已经看过了用Ruby创建HTML文件和显示它,下面我们来看看如何将Ruby嵌入HTML文档中。
有好几个包支持我们将Ruby嵌入其它文档中,特别是HTML页面,一般来说,这叫做eRuby,它的实现也有好几种,比如eruby和erb。下面的部分将介绍eruby。
将Ruby脚本嵌入HTML非常有用,我们不仅能像ASP,JSP,PHP一样使用它,而且还能发挥Ruby的力量。
使用eruby
eruby
简单来说就像一个过滤器,对于输入的文件中的普通HTML内容,它将不会做什么处理,而对下面的格式的代码进行特殊处理:表达式意义
<%
ruby code%>
将定界符内的Ruby代码转换为它的结果输出<%=
ruby expression%>
输出这个表达式的值到HTML中<%#
ruby code%>
代码注释,这些内容将被忽略。对测试来说可能有用。调用eruby的方法如下:
eruby [ options ] [ document ]
如果document忽略,则eruby将从标准输入读取。eruby的命令行参数如下:
OptionDescription-d
,--debug
设置$DEBUG 为true
.-K
kcode 指定不同的编码系统(coding system 参见137页)-M
mode 指定运行模式,为下面之一:f
过滤模式c
CGI 模式(将错误打印为HTML, 设置$SAFE=1)n
NPH-CGI 模式(打印额外的头部为HTTP,设置$SAFE=1)-n
,--noheader
禁止CGI头部( header)输出-v
,--verbose
允许详细(verbose )模式--version
打印出版本信息并退出程序让我们来看一些简单的例子,假如我们给eruby运行时候的输入为下面的内容:
This text is <% a = 100; puts "#{a}% Live!" %>
eruby
将把<%和%>之间的Ruby代码换成它执行后的值然后显示出来。This text is 100% Live!
使用 <%= 的形式,直接将后面的表达式的值输出,比如,我们的输入如下:
<%a = 100%>This text is almost <%=a%> degrees! Cool!将=a替换为a的实际值,如下:
This text is almost 100 degrees! Cool!
当然,你也可以将Ruby嵌入更复杂的文档,比如HTML。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>eruby example</title> </head> <body> <h1>Enumeration</h1> <ul> <%(1..10).each do|i|%> <li>number <%=i%></li> <%end%> </ul> <h1>Environment variables</h1> <table> <%ENV.keys.sort.each do |key|%> <tr> <th><%=key%></th><td><%=ENV[key]%></td> </tr> <%end%> </table> </body> </html>
在 Apache中安装eruby
你可以安装一个使用eRuby的Apache服务器来自动解析嵌入Ruby的文档,就像PHP那样。你可以将嵌入Ruby的文档命名为以`.rhtml
'' 为后缀,然后设置web服务器来调用eruby来解析这些文件输出想要的HTML。
为了在Apache中使用eruby,需要以下几步。
- 将可执行的
eruby
程序拷贝到cgi-bin
目录 - 在
httpd.conf
文件中增加如下两行:AddType application/x-httpd-eruby .rhtml Action application/x-httpd-eruby /cgi-bin/eruby
- 如果需要,你可以在你的
DirectoryIndex
指令中加入index.rhtml
,这样,如果你的目录下面如果没有index.html文件,则就会使用index.rhtml文件作为index页。比如下面的例子DirectoryIndex index.html index.shtml index.rhtml
当然,你也可以用一个作用于一个全站点范围的Ruby脚本
Of course, you could also simply use a site-wide Ruby script as well.DirectoryIndex index.html index.shtml /cgi-bin/index.rb
就是如此,你可以在HTML文档中加入嵌入的Ruby脚本来动态地创建表单和内容。但也请你阅读一下从497页开始的CGI库。
提高性能
你可以使用Ruby为web编写CGI程序,但是,如同其它CGI程序一样,默认得设置下,对每个cgi页面的请求都将产生一个新的Ruby进程,这将占用服务器很多的资源,而且容易引起性能的下降。Apache web服务器通过使用可装载的模块来解决这个问题。
一般来说,这些模块都会动态的被载入,而且会成为Web服务器进程的一部分,也就是说不需要每次有CGI请求进来都产生一个Ruby解释器程序,Web服务器就充当了解释器的角色。所以我们会用到mod_ruby,它会将Ruby解释器连接(links)到Web服务器,关于它的具体信息可以看它的发布程序附带的README文件。
一旦你安装配置好之后,你就可以像原来一样运行Ruby脚本,不同的是现在地速度应该是快很多了。