Ruby CGI 编程

在 Ruby 中,CGI(Common Gateway Interface) 是一种用于开发 Web 应用程序的技术,允许 Web 服务器与外部程序(如 Ruby 脚本)交互,生成动态网页内容。Ruby 提供了内置的 cgi 库,简化了 CGI 编程的开发。以下是对 Ruby CGI 编程的中文讲解,涵盖基本概念、环境搭建、核心功能、示例代码及注意事项,力求简洁清晰。


1. CGI 简介

CGI 是一种 Web 服务器与外部程序通信的协议。Ruby 的 cgi 库提供了处理 HTTP 请求、解析参数、生成 HTML 响应等功能,适用于动态生成网页内容或处理表单数据。

特点

  • 简单易用,适合小型 Web 应用。
  • 跨平台,与大多数 Web 服务器(如 Apache、Nginx)兼容。
  • 性能较低,现代 Web 开发多使用框架(如 Rails)替代。

2. 环境搭建

先决条件

  • 安装 Ruby:确保 Ruby 已安装(ruby -v 检查版本)。
  • Web 服务器:需要配置支持 CGI 的服务器(如 Apache)。
  • Apache 配置(以 Ubuntu 为例):
    1. 安装 Apache:
      bash sudo apt-get install apache2
    2. 启用 CGI 模块:
      bash sudo a2enmod cgi
    3. 配置 CGI 目录(通常 /usr/lib/cgi-bin),编辑 /etc/apache2/sites-available/000-default.conf
      apache <Directory "/usr/lib/cgi-bin"> Options +ExecCGI AddHandler cgi-script .rb </Directory>
    4. 重启 Apache:
      bash sudo service apache2 restart
  • 文件权限:CGI 脚本需可执行权限(chmod +x script.rb)。
  • 文件位置:将 Ruby CGI 脚本放入 CGI 目录(如 /usr/lib/cgi-bin)。

安装 cgi 库

Ruby 标准库已包含 cgi 模块,无需额外安装。直接在脚本中引入:

require 'cgi'

3. CGI 脚本结构

一个典型的 Ruby CGI 脚本包含以下部分:

  1. Shebang 行:指定 Ruby 解释器路径。
  2. HTTP 头:输出 Content-type(通常为 text/html)。
  3. 内容:动态生成的 HTML 或其他响应。

基本示例

#!/usr/bin/ruby
require 'cgi'

puts "Content-type: text/html\n\n"
puts "<html><body>"
puts "<h1>Hello, CGI!</h1>"
puts "</body></html>"

保存与运行

  1. 保存为 /usr/lib/cgi-bin/hello.rb
  2. 设置可执行权限:
   chmod +x /usr/lib/cgi-bin/hello.rb
  1. 通过浏览器访问:http://localhost/cgi-bin/hello.rb
    输出:网页显示 <h1>Hello, CGI!</h1>

4. 处理 HTTP 请求

CGI 脚本通过环境变量和 CGI 类处理 HTTP 请求(如 GET、POST 参数)。

获取请求参数

  • GET 参数:通过 CGI.new.params 获取。
  # URL: http://localhost/cgi-bin/test.rb?name=Alice&age=25
  #!/usr/bin/ruby
  require 'cgi'

  cgi = CGI.new
  puts "Content-type: text/html\n\n"
  puts "<html><body>"
  puts "<p>Name: #{cgi['name']}</p>"
  puts "<p>Age: #{cgi['age']}</p>"
  puts "</body></html>"

输出

  Name: Alice
  Age: 25
  • POST 参数:通过 HTML 表单提交。
  <!-- form.html -->
  <form action="/cgi-bin/form.rb" method="post">
      Name: <input type="text" name="name">
      Age: <input type="text" name="age">
      <input type="submit" value="Submit">
  </form>
  # form.rb
  #!/usr/bin/ruby
  require 'cgi'

  cgi = CGI.new
  puts "Content-type: text/html\n\n"
  puts "<html><body>"
  puts "<p>Name: #{cgi['name']}</p>"
  puts "<p>Age: #{cgi['age']}</p>"
  puts "</body></html>"

环境变量

CGI 脚本可以通过 ENV 访问 HTTP 请求的环境变量。

#!/usr/bin/ruby
require 'cgi'

puts "Content-type: text/html\n\n"
puts "<html><body>"
puts "<p>请求方法: #{ENV['REQUEST_METHOD']}</p>"
puts "<p>用户代理: #{ENV['HTTP_USER_AGENT']}</p>"
puts "</body></html>"

输出(示例):

请求方法: GET
用户代理: Mozilla/5.0 ...

5. 生成 HTML

CGI 类提供方法简化 HTML 生成。

使用 CGI#out

自动生成 HTTP 头和 HTML。

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
cgi.out do
  "<html><body><h1>Welcome, #{cgi['name'] || 'Guest'}!</h1></body></html>"
end

HTML 转义

防止 XSS 攻击,使用 CGI.escapeHTML 转义用户输入。

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
name = CGI.escapeHTML(cgi['name'] || 'Guest')
puts "Content-type: text/html\n\n"
puts "<html><body><p>Hello, #{name}!</p></body></html>"

6. 处理 Cookies

CGI 类支持设置和读取 Cookies。

设置 Cookie

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
cookie = CGI::Cookie.new('name' => 'user_id', 'value' => '12345', 'expires' => Time.now + 3600)
cgi.out('cookie' => [cookie]) do
  "<html><body><p>Cookie set for user_id: 12345</p></body></html>"
end

读取 Cookie

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
user_id = cgi.cookies['user_id'].value.first
puts "Content-type: text/html\n\n"
puts "<html><body><p>User ID: #{user_id}</p></body></html>"

7. 文件上传

CGI 支持处理表单文件上传(multipart/form-data)。

HTML 表单

<form action="/cgi-bin/upload.rb" method="post" enctype="multipart/form-data">
    File: <input type="file" name="file">
    <input type="submit" value="Upload">
</form>

处理上传

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
file = cgi.params['file'].first
filename = file.original_filename
content = file.read

# 保存文件
File.open("uploads/#{filename}", "wb") { |f| f.write(content) }

puts "Content-type: text/html\n\n"
puts "<html><body><p>File #{filename} uploaded!</p></body></html>"

说明

  • file.original_filename:获取文件名。
  • file.read:读取文件内容。
  • 确保 uploads 目录存在且有写权限。

8. 异常处理

CGI 脚本需处理潜在错误(如参数缺失、文件权限)。

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
begin
  name = cgi['name'] || raise("Name 参数缺失")
  puts "Content-type: text/html\n\n"
  puts "<html><body><p>Hello, #{CGI.escapeHTML(name)}!</p></body></html>"
rescue => e
  puts "Content-type: text/html\n\n"
  puts "<html><body><p>错误: #{CGI.escapeHTML(e.message)}</p></body></html>"
end

9. 注意事项

  • 性能:CGI 每次请求启动新进程,性能较低,适合小型应用。大型项目推荐 Rails 或 Sinatra。
  • 安全性
  • 使用 CGI.escapeHTML 防止 XSS。
  • 验证用户输入,防止 SQL 注入(结合数据库操作时)。
  • 限制文件上传大小和类型。
  • 权限:确保 CGI 脚本和目录(如 /usr/lib/cgi-bin)有正确权限。
  • 调试:检查 Web 服务器日志(/var/log/apache2/error.log)定位错误。
  • 现代替代:Rails、Sinatra 等框架更适合现代 Web 开发,提供更高性能和安全性。

10. 综合示例

#!/usr/bin/ruby
require 'cgi'

cgi = CGI.new
begin
  name = cgi['name'] || 'Guest'
  cookie = CGI::Cookie.new('name' => 'last_user', 'value' => name, 'expires' => Time.now + 3600)
  cgi.out('cookie' => [cookie]) do
    <<-HTML
      <html>
      <body>
        <h1>Welcome, #{CGI.escapeHTML(name)}!</h1>
        <form action="/cgi-bin/form.rb" method="post">
          Name: <input type="text" name="name">
          <input type="submit" value="Submit">
        </form>
        <p>Last user: #{CGI.escapeHTML(cgi.cookies['last_user'].value.first)}</p>
      </body>
      </html>
    HTML
  end
rescue => e
  cgi.out do
    "<html><body><p>错误: #{CGI.escapeHTML(e.message)}</p></body></html>"
  end
end

保存:保存为 /usr/lib/cgi-bin/form.rb,设置权限(chmod +x)。
访问http://localhost/cgi-bin/form.rb?name=Alice


11. 总结

Ruby 的 cgi 库提供简单的方式开发 CGI 脚本,支持处理 GET/POST 请求、Cookies、文件上传等功能。通过 CGI.newcgi.out 生成动态 HTML,结合异常处理和 CGI.escapeHTML 确保安全性。CGI 适合快速原型或小型应用,但性能限制使其在现代开发中逐渐被 Rails 等框架取代。

如果你有具体问题(如复杂表单处理、与数据库结合)或需要更多示例,请告诉我!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注