Apache HTTP Server 版本 2.4
相关模块 | 相关指令 |
---|---|
CGI(通用网关接口)定义了一种 Web 服务器与外部内容生成程序交互的方式,这些程序通常被称为 CGI 程序或 CGI 脚本。它是一种在您的网站上放置动态内容的简单方法,可以使用您最熟悉的任何编程语言。本文档将介绍如何在您的 Apache Web 服务器上设置 CGI 以及开始编写 CGI 程序。
为了使您的 CGI 程序正常工作,您需要配置 Apache 以允许 CGI 执行。有几种方法可以做到这一点。
httpd.conf
中,您需要确保 LoadModule
指令没有被注释掉。正确配置的指令可能如下所示LoadModule cgid_module modules/mod_cgid.so在 Windows 上,或使用非线程化的 MPM(如 prefork),正确配置的指令可能如下所示
LoadModule cgi_module modules/mod_cgi.so
ScriptAlias
指令告诉 Apache 特定目录是为 CGI 程序预留的。Apache 将假定此目录中的每个文件都是 CGI 程序,并在客户端请求该特定资源时尝试执行它。
ScriptAlias
指令如下所示
ScriptAlias "/cgi-bin/" "/usr/local/apache2/cgi-bin/"
显示的示例来自您的默认 httpd.conf
配置文件,如果您在默认位置安装了 Apache。 ScriptAlias
指令与 Alias
指令非常相似,后者定义一个要映射到特定目录的 URL 前缀。 Alias
和 ScriptAlias
通常用于位于 DocumentRoot
目录之外的目录。 Alias
和 ScriptAlias
之间的区别在于 ScriptAlias
具有额外的含义,即该 URL 前缀下的所有内容都将被视为 CGI 程序。因此,上面的示例告诉 Apache 任何以 /cgi-bin/
开头的资源请求都应从 /usr/local/apache2/cgi-bin/
目录提供服务,并且应被视为 CGI 程序。
例如,如果请求 URL http://www.example.com/cgi-bin/test.pl
,Apache 将尝试执行文件 /usr/local/apache2/cgi-bin/test.pl
并返回输出。当然,该文件必须存在,并且是可执行的,并且以特定方式返回输出,否则 Apache 将返回错误消息。
出于安全原因,CGI 程序通常被限制在 ScriptAlias
的目录中。通过这种方式,管理员可以严格控制谁被允许使用 CGI 程序。但是,如果采取了适当的安全预防措施,则没有理由不能从任意目录运行 CGI 程序。例如,您可能希望让用户使用 UserDir
指令在其主目录中拥有 Web 内容。如果他们想拥有自己的 CGI 程序,但没有访问主 cgi-bin
目录的权限,他们将需要能够在其他地方运行 CGI 程序。
在任意目录中允许 CGI 执行有两个步骤。首先,必须使用 AddHandler
或 SetHandler
指令激活 cgi-script
处理程序。其次,必须在 Options
指令中指定 ExecCGI
。
您可以在主服务器配置文件中显式使用 Options
指令,以指定在特定目录中允许 CGI 执行
<Directory "/usr/local/apache2/htdocs/somedir"> Options +ExecCGI </Directory>
上面的指令告诉 Apache 允许执行 CGI 文件。您还需要告诉服务器哪些文件是 CGI 文件。以下 AddHandler
指令告诉服务器将所有扩展名为 cgi
或 pl
的文件视为 CGI 程序
AddHandler cgi-script .cgi .pl
.htaccess
教程 展示了如果您没有访问 httpd.conf
的权限,如何激活 CGI 程序。
要允许用户目录中任何以 .cgi
结尾的文件执行 CGI 程序,您可以使用以下配置。
<Directory "/home/*/public_html"> Options +ExecCGI AddHandler cgi-script .cgi </Directory>
如果您希望指定用户目录的 cgi-bin
子目录,其中所有内容都将被视为 CGI 程序,您可以使用以下内容。
<Directory "/home/*/public_html/cgi-bin"> Options ExecCGI SetHandler cgi-script </Directory>
``常规''编程和 CGI 编程之间有两个主要区别。
首先,CGI 程序的所有输出都必须以 MIME 类型 标头开头。这是一个 HTTP 标头,它告诉客户端它正在接收什么类型的內容。大多数情况下,它看起来像
Content-type: text/html
其次,您的输出需要以 HTML 或浏览器能够显示的其他格式呈现。大多数情况下,这将是 HTML,但有时您可能会编写一个输出 gif 图像或其他非 HTML 内容的 CGI 程序。
除了这两点之外,编写 CGI 程序看起来与您可能编写的任何其他程序非常相似。
以下是一个示例 CGI 程序,它向您的浏览器打印一行。输入以下内容,将其保存到名为 first.pl
的文件中,并将其放在您的 cgi-bin
目录中。
#!/usr/bin/perl print "Content-type: text/html\n\n"; print "Hello, World.";
即使您不熟悉 Perl,您也应该能够看到这里发生了什么。第一行告诉 Apache(或您碰巧运行的任何 shell)该程序可以通过将文件馈送到 /usr/bin/perl
位置找到的解释器来执行。第二行打印我们讨论过的内容类型声明,后面跟着两个回车换行对。这在标头之后放置了一条空行,以指示 HTTP 标头的结束和正文的开始。第三行打印字符串“Hello, World.”。就这样结束了。
如果您打开您喜欢的浏览器并告诉它获取地址
http://www.example.com/cgi-bin/first.pl
或者您放置文件的位置,您将在浏览器窗口中看到一行 Hello, World.
出现。它不是很有趣,但一旦您让它正常工作,您就有很大机会让几乎所有东西都正常工作。
当您尝试从 Web 访问您的 CGI 程序时,您可能会在浏览器中看到四种基本情况
请记住,服务器不是以您的身份运行的。也就是说,当服务器启动时,它以非特权用户的权限运行——通常是 nobody
或 www
——因此它需要额外的权限才能执行您拥有的文件。通常,为文件提供足够的权限以便 nobody
可以执行它的方法是为每个人授予该文件的执行权限
chmod a+x first.pl
此外,如果您的程序从任何其他文件读取或写入任何其他文件,则这些文件需要具有正确的权限才能允许这样做。
当您从命令行运行程序时,您会有一些信息传递给 shell,而您无需考虑它。例如,您有一个 PATH
,它告诉 shell 它可以在哪里查找您引用的文件。
当程序通过 Web 服务器作为 CGI 程序运行时,它可能没有相同的 PATH
。您在 CGI 程序中调用的任何程序(例如 sendmail
)都需要通过完整路径指定,以便 shell 在尝试执行您的 CGI 程序时能够找到它们。
这种情况的常见表现形式是 CGI 程序第一行中指示的脚本解释器(通常是 perl
)的路径,它看起来像
#!/usr/bin/perl
确保这确实是解释器的路径。
如果您的 CGI 程序依赖于非标准 环境变量,您需要确保 Apache 传递了这些变量。
当您在环境中丢失 HTTP 标头时,请确保它们按照 RFC 2616 第 4.2 节的格式进行格式化:标头名称必须以字母开头,后面只能跟字母、数字或连字符。任何违反此规则的标头将被静默丢弃。
大多数情况下,当 CGI 程序失败时,是因为程序本身存在问题。当您掌握了 CGI 的基本知识后,这种情况尤其如此,您不再犯上述两个错误。首先要做的是确保您的程序在通过 Web 服务器测试之前从命令行运行。例如,尝试
cd /usr/local/apache2/cgi-bin
./first.pl
(不要调用 perl
解释器。shell 和 Apache 应该使用脚本第一行上的 路径信息 找到解释器。)
您首先看到程序写入的内容应该是一组 HTTP 标头,包括 Content-Type
,后面跟着一个空行。如果您看到其他任何内容,Apache 将在您尝试通过服务器运行它时返回 Premature end of script headers
错误。有关更多详细信息,请参阅上面的 编写 CGI 程序。
错误日志是您的朋友。任何出错都会在错误日志中生成消息。您应该始终首先查看那里。如果托管网站的位置不允许您访问错误日志,您可能应该将网站托管在其他地方。学会阅读错误日志,您会发现几乎所有问题都可以快速识别并快速解决。
suexec 支持程序允许 CGI 程序在不同的用户权限下运行,具体取决于它们位于哪个虚拟主机或用户主目录中。Suexec 具有非常严格的权限检查,任何检查失败都会导致您的 CGI 程序以 Premature end of script headers
失败。
要检查您是否正在使用 suexec,请运行 apachectl -V
并检查 SUEXEC_BIN
的位置。如果 Apache 在启动时在那里找到一个 suexec
二进制文件,则 suexec 将被激活。
除非您完全了解 suexec,否则您不应该使用它。要禁用 suexec,只需删除(或重命名)由 SUEXEC_BIN
指向的 suexec
二进制文件,然后重新启动服务器。如果您在阅读了有关 suexec 的信息后,仍然希望使用它,那么运行 suexec -V
以找到 suexec 日志文件的位置,并使用该日志文件找到您违反的策略。
随着您在 CGI 编程方面变得更加熟练,了解幕后发生的事情将变得很有用。具体来说,浏览器和服务器如何相互通信。因为虽然编写一个打印“Hello, World.”的程序很好,但它并不特别有用。
环境变量是在您使用计算机时围绕您的值。它们是有用的东西,例如您的路径(当您键入命令时,计算机在其中搜索实现该命令的实际文件)、您的用户名、您的终端类型等等。要查看您正常、日常环境变量的完整列表,请在命令提示符下键入 env
。
在 CGI 事务期间,服务器和浏览器也会设置环境变量,以便它们可以相互通信。这些东西包括浏览器类型(Netscape、IE、Lynx)、服务器类型(Apache、IIS、WebSite)、正在运行的 CGI 程序的名称等等。
这些变量可供 CGI 程序员使用,并且是客户端-服务器通信故事的一半。所需变量的完整列表位于 Common Gateway Interface RFC 中。
这个简单的 Perl CGI 程序将显示所有正在传递的环境变量。Apache 发行版的 cgi-bin
目录中包含两个类似的程序。请注意,某些变量是必需的,而另一些是可选的,因此您可能会看到一些不在官方列表中的变量。此外,Apache 提供了许多不同的方法供您 将您自己的环境变量 添加到默认提供的基本环境变量中。
#!/usr/bin/perl use strict; use warnings; print "Content-type: text/html\n\n"; foreach my $key (keys %ENV) { print "$key --> $ENV{$key}<br>"; }
服务器和客户端之间的其他通信通过标准输入 (STDIN
) 和标准输出 (STDOUT
) 进行。在正常的日常环境中,STDIN
表示键盘,或程序被赋予作用的文件,而 STDOUT
通常表示控制台或屏幕。
当您将 Web 表单 POST
到 CGI 程序时,该表单中的数据将捆绑成一种特殊格式,并通过 STDIN
传递到您的 CGI 程序。然后,程序可以像从键盘或文件输入一样处理这些数据
“特殊格式”非常简单。字段名称及其值用等号 (=) 连接在一起,值对用与号 (&) 连接在一起。空格、与号和等号等不方便的字符将转换为它们的十六进制等效项,以防止它们妨碍工作。整个数据字符串可能看起来像
name=Rich%20Bowen&city=Lexington&state=KY&sidekick=Squirrel%20Monkey
您有时也会看到这种类型的字符串附加到 URL。当这样做时,服务器将该字符串放入名为 QUERY_STRING
的环境变量中。这称为 GET
请求。您的 HTML 表单通过在 FORM
标签中设置 METHOD
属性来指定使用 GET
还是 POST
来传递数据。
然后,您的程序负责将该字符串拆分为有用的信息。幸运的是,有库和模块可用于帮助您处理这些数据,以及处理 CGI 程序的其他方面。
当您编写 CGI 程序时,您应该考虑使用代码库或模块来为您完成大部分繁重的工作。这会导致更少的错误和更快的开发。
如果您正在 Perl 中编写 CGI 程序,则可以在 CPAN 上获得模块。最流行的模块是 CGI.pm
。您也可以考虑 CGI::Lite
,它实现了最小的功能集,这在大多数程序中都是您所需要的。
如果您正在 C 中编写 CGI 程序,则有多种选择。其中之一是来自 https://web.mit.edu/wwwdev/www/cgic.html 的 CGIC
库。
当前的 CGI 规范可在 Common Gateway Interface RFC 中找到。
当您发布有关遇到的 CGI 问题的疑问时,无论是发布到邮件列表还是新闻组,请确保提供有关发生的事情、您期望发生的事情以及实际发生的事情与预期不同的方式、您正在运行的服务器、您的 CGI 程序的语言以及(如果可能)导致问题的代码的足够信息。这将使查找问题变得更加简单。
请注意,有关 CGI 问题的疑问绝不应发布到 Apache 错误数据库,除非您确定在 Apache 源代码中找到了问题。