Ruby 和 Web

优质
小牛编辑
131浏览
2023-12-01
Ruby对互联网来说并不陌生,不只是因为你可以用它来写SMTP服务器,FTP服务器,或者web服务器,你还可以用它来完成通常的任务,比如CGI编程或者作为PHP的一个替代品。

编写 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.escapeCGI.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>' )
结果:
&lt;a href=&quot;/mp3&quot;&gt;Click Here&lt;/a&gt;

而且,你也可以只对HTML的一部分标记进行转义,而不是全部:

require 'cgi'
puts CGI.escapeElement('<hr><a href="/mp3">Click Here</a><br>','A')
produces:
<hr>&lt;a href=&quot;/mp3&quot;&gt;Click Here&lt;/a&gt;<br>

这里又有A标记被转义了,其它标记都没有变化。

每个这样的转义方法都有一个un-开头的版本,来恢复这个转义之前的字符串。

表单(Forms)

使用CGI类你有两种方法访问HTML传过来的参数。比如我们有一个URL/cgi-bin/lookup?player=Miles%20Davis&year=1958,你可以用CGI#[ ]方法直接访问player和year变量:

require 'cgi'cgi = CGI.newcgi['player'] ?["Miles Davis"]cgi['year'] ?["1958"]

或者,你可以把所有参数放入一个Hash中,再从这个哈希查询参数。

require 'cgi'cgi = CGI.newh = cgi.paramsh['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>
   

当用户下次访问这个页面时,你可以取得cookieCustIDPart,然后将它们显示在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.-Kkcode 指定不同的编码系统(coding system 参见137页)-Mmode 指定运行模式,为下面之一: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脚本,不同的是现在地速度应该是快很多了。