Ruby CGI方法

在 Ruby 中,CGI(Common Gateway Interface) 编程通过内置的 cgi 库提供了一系列方法,用于处理 Web 请求、生成动态内容、管理 Cookies 和处理文件上传等。以下是对 Ruby cgi 库中常用方法的中文讲解,涵盖核心功能、用法及示例,力求简洁清晰,避免重复之前的内容(如 CGI 编程概述)。内容将聚焦于 CGI 类的方法及其实际应用。


1. CGI 类概述

Ruby 的 cgi 模块提供 CGI 类,用于处理 HTTP 请求(GET、POST)、生成 HTML 响应、管理 Cookies 和处理表单数据。所有 CGI 脚本需引入:

require 'cgi'

2. 创建 CGI 对象

  • CGI.new:初始化 CGI 对象,解析 HTTP 请求。
  cgi = CGI.new

参数

  • html:指定 HTML 版本(默认 HTML4),如 "html5"
  cgi = CGI.new("html5")

3. 常用 CGI 方法

以下是 CGI 类中常用的实例方法和类方法,分为请求处理、响应生成、Cookies 和工具方法。

3.1 请求处理方法

  • cgi.params:获取请求参数(GET 或 POST),返回哈希,键为参数名,值为数组。
  cgi = CGI.new
  name = cgi.params['name'][0]  # 获取 name 参数的第一个值
  puts "Content-type: text/html\n\n"
  puts "<p>Name: #{CGI.escapeHTML(name)}</p>"

示例 URLhttp://localhost/cgi-bin/test.rb?name=Alice
输出Name: Alice

  • cgi[key]:快捷获取参数值(返回字符串,单值时更简洁)。
  puts "<p>Name: #{CGI.escapeHTML(cgi['name'])}</p>"
  • cgi.multipart?:检查请求是否为 multipart/form-data(常用于文件上传)。
  puts cgi.multipart?  # 输出:true(如果是文件上传表单)
  • cgi.cookies:获取请求中的 Cookies,返回哈希。
  user_id = cgi.cookies['user_id'][0] || 'Guest'
  puts "<p>User ID: #{CGI.escapeHTML(user_id)}</p>"

3.2 响应生成方法

  • cgi.out(options = {}):生成 HTTP 响应头和内容,自动添加 Content-type
  cgi = CGI.new
  cgi.out do
    "<html><body><h1>Hello, CGI!</h1></body></html>"
  end

选项

  • type:Content-type(如 "text/html")。
  • status:HTTP 状态码(如 "404 Not Found")。
  • cookie:Cookies 数组。
  cookie = CGI::Cookie.new('name' => 'user_id', 'value' => '12345')
  cgi.out('cookie' => [cookie], 'type' => 'text/html') do
    "<html><body><p>Cookie set!</p></body></html>"
  end
  • cgi.header(options = {}):仅生成 HTTP 响应头。
  puts cgi.header('type' => 'text/plain')
  puts "Plain text response"

3.3 HTML 生成方法

CGI 类提供方法生成 HTML 标签(基于 HTML 版本)。

  • cgi.element_name(attributes = {}):生成指定 HTML 标签,如 cgi.h1, cgi.p
  cgi = CGI.new("html5")
  puts cgi.out do
    cgi.html do
      cgi.body do
        cgi.h1 { "Welcome" } + cgi.p { "This is a paragraph." }
      end
    end
  end

输出

  <html>
  <body>
  <h1>Welcome</h1>
  <p>This is a paragraph.</p>
  </body>
  </html>
  • cgi.form(attributes = {}, &block):生成表单。
  puts cgi.out do
    cgi.form('action' => '/cgi-bin/submit.rb', 'method' => 'post') do
      cgi.text_field('name') + cgi.submit('Submit')
    end
  end

输出

  <form action="/cgi-bin/submit.rb" method="post">
  <input type="text" name="name"><input type="submit" value="Submit">
  </form>

3.4 Cookies 管理

  • CGI::Cookie.new(name, value):创建 Cookie 对象。
  cookie = CGI::Cookie.new(
    'name' => 'user_id',
    'value' => '12345',
    'expires' => Time.now + 3600,  # 1 小时后过期
    'path' => '/',
    'secure' => true
  )
  • 设置 Cookie:通过 cgi.outcgi.header 设置。
  cgi.out('cookie' => [cookie]) { "<p>Cookie set!</p>" }

3.5 工具方法(类方法)

  • CGI.escape(string):对 URL 编码。
  puts CGI.escape("name=Alice & Bob")  # 输出:name%3DAlice+%26+Bob
  • CGI.unescape(string):解码 URL 编码。
  puts CGI.unescape("name%3DAlice+%26+Bob")  # 输出:name=Alice & Bob
  • CGI.escapeHTML(string):转义 HTML 特殊字符,防止 XSS。
  puts CGI.escapeHTML("<script>alert('xss')</script>")  # 输出:&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;
  • CGI.unescapeHTML(string):解码 HTML 转义字符。
  puts CGI.unescapeHTML("&lt;p&gt;Hello&lt;/p&gt;")  # 输出:<p>Hello</p>

4. 文件上传处理

处理 multipart/form-data 表单上传的文件。

表单示例

<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'][0]
filename = CGI.escapeHTML(file.original_filename)
content = file.read

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

cgi.out do
  "<html><body><p>File #{filename} uploaded!</p></body></html>"
end

说明

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

5. 异常处理

CGI 脚本需处理参数缺失或无效输入。

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

cgi = CGI.new
begin
  name = cgi['name'] || raise("Name 参数缺失")
  cgi.out do
    "<html><body><p>Hello, #{CGI.escapeHTML(name)}!</p></body></html>"
  end
rescue => e
  cgi.out('status' => '400') do
    "<html><body><p>错误: #{CGI.escapeHTML(e.message)}</p></body></html>"
  end
end

6. 注意事项

  • 安全性
  • 使用 CGI.escapeHTML 转义用户输入,防止 XSS。
  • 验证上传文件的类型和大小,防止恶意上传。
  • 避免直接拼接 SQL 查询,结合数据库时使用参数绑定。
  • 性能:CGI 每次请求启动新进程,适合小型应用,复杂项目推荐 Rails/Sinatra。
  • 调试:检查 Web 服务器日志(如 /var/log/apache2/error.log)。
  • 环境变量:通过 ENV 访问 REQUEST_METHOD, QUERY_STRING 等。
  puts ENV['REQUEST_METHOD']  # 输出:GET 或 POST
  • HTML 版本:初始化 CGI.new 时指定 HTML 版本(如 "html5"),确保生成正确的标签。

7. 综合示例

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

cgi = CGI.new("html5")
cookie = CGI::Cookie.new('name' => 'last_user', 'value' => cgi['name'] || 'Guest', 'expires' => Time.now + 3600)

begin
  name = cgi['name'] || 'Guest'
  cgi.out('cookie' => [cookie]) do
    cgi.html do
      cgi.body do
        cgi.h1 { "Welcome, #{CGI.escapeHTML(name)}!" } +
        cgi.form('action' => '/cgi-bin/form.rb', 'method' => 'post') do
          cgi.p { "Name: " + cgi.text_field('name') } +
          cgi.submit('Submit')
        end +
        cgi.p { "Last user: #{CGI.escapeHTML(cgi.cookies['last_user'][0] || 'None')}" }
      end
    end
  end
rescue => e
  cgi.out('status' => '400') 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
功能:显示欢迎消息、表单,并通过 Cookie 记录上一个用户。


8. 总结

Ruby 的 CGI 类提供了丰富的实例方法(如 params, out, form)和类方法(如 escapeHTML, escape),用于处理 HTTP 请求、生成动态 HTML、管理 Cookies 和文件上传。结合异常处理和转义方法,CGI 脚本可以安全处理用户输入。尽管 CGI 适合快速开发小型 Web 应用,但性能限制使其在现代开发中常被 Rails 或 Sinatra 替代。

如果你需要更具体的方法讲解(如特定 HTML 标签生成)或复杂示例,请告诉我!

类似文章

发表回复

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