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 为例):
- 安装 Apache:
bash sudo apt-get install apache2
- 启用 CGI 模块:
bash sudo a2enmod cgi
- 配置 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>
- 重启 Apache:
bash sudo service apache2 restart
- 安装 Apache:
- 文件权限:CGI 脚本需可执行权限(
chmod +x script.rb
)。 - 文件位置:将 Ruby CGI 脚本放入 CGI 目录(如
/usr/lib/cgi-bin
)。
安装 cgi 库
Ruby 标准库已包含 cgi
模块,无需额外安装。直接在脚本中引入:
require 'cgi'
3. CGI 脚本结构
一个典型的 Ruby CGI 脚本包含以下部分:
- Shebang 行:指定 Ruby 解释器路径。
- HTTP 头:输出
Content-type
(通常为text/html
)。 - 内容:动态生成的 HTML 或其他响应。
基本示例:
#!/usr/bin/ruby
require 'cgi'
puts "Content-type: text/html\n\n"
puts "<html><body>"
puts "<h1>Hello, CGI!</h1>"
puts "</body></html>"
保存与运行:
- 保存为
/usr/lib/cgi-bin/hello.rb
。 - 设置可执行权限:
chmod +x /usr/lib/cgi-bin/hello.rb
- 通过浏览器访问:
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.new
和 cgi.out
生成动态 HTML,结合异常处理和 CGI.escapeHTML
确保安全性。CGI 适合快速原型或小型应用,但性能限制使其在现代开发中逐渐被 Rails 等框架取代。
如果你有具体问题(如复杂表单处理、与数据库结合)或需要更多示例,请告诉我!