©
本文档使用
php.cn手册 发布
你可以用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主要来帮助你更方便的编写CGI脚本,使用它,你可以操纵表单(form),cookies和环境变量,维护有状态的session等等。关于它的文档在第497页,但是我们在这里要先看一下它大体的功能。
当处理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') |
<hr><a href="/mp3">Click Here</a><br> |
这里又有A标记被转义了,其它标记都没有变化。
每个这样的转义方法都有一个un-开头的版本,来恢复这个转义之前的字符串。
使用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"] |
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 } } } } |
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在客户机上存放各种有用的信息,你可以创建一个有名字的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" } } |
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> |
当用户下次访问这个页面时,你可以取得cookie CustID
和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") } } } |
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> |
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页面,一般来说,这叫做eRuby,它的实现也有好几种,比如eruby和erb。下面的部分将介绍eruby。
将Ruby脚本嵌入HTML非常有用,我们不仅能像ASP,JSP,PHP一样使用它,而且还能发挥Ruby的力量。
eruby
简单来说就像一个过滤器,对于输入的文件中的普通HTML内容,它将不会做什么处理,而对下面的格式的代码进行特殊处理:
表达式 | 意义 | |||||||
<% ruby code %> |
将定界符内的Ruby代码转换为它的结果输出 | |||||||
<%= ruby expression %> |
输出这个表达式的值到HTML中 | |||||||
<%# ruby code %> |
代码注释,这些内容将被忽略。对测试来说可能有用。 | |||||||
调用eruby的方法如下:
eruby [ options ] [ document ] |
如果document忽略,则eruby将从标准输入读取。eruby的命令行参数如下:
|
让我们来看一些简单的例子,假如我们给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! |
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> |
你可以安装一个使用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脚本,不同的是现在地速度应该是快很多了。