纸上得来终觉浅,绝知此事要躬行。
1. CGI
CGI(
Common Gateway Interface
)通用网关接口,CGI
技术可以让用户使用服务器所支持的编程语言(C/C++/Perl/Bash/PHP
)来处理任何操作,最初的设计目的是增加用户的交互性并提供一些对服务器的基本访问,如数据库的查询、数据添加等工作。
CGI 的工作原理
CGI
允许Web
页面通过服务器执行任何程序,当服务器收到执行的请求时会将请求信息头和一些环境变量传送给CGI
脚本,CGI
脚本在独立于Apache
服务器外的内存空间内运行,并将运行结果返回给Apache
,最后Apache
将结果包含在HTTP
页中发送给用户。
CGI 的实现方式
- 在早期的
Apache
服务器中,CGI
是通过mod_CGI
模块来实现的 - 目前的
Apache
版本中,Apache
会根据不同的平台自动选择运行不同的CGI
模块 - 在非线程平台(
worker
)上使用mod_cgi
模块,在线程型平台(prefork
)上使用mod_cgid
模块
1.1 mod_cgi 模块
启用只需在配置文件家在对应的模块就可启动CGI
功能。
LoadModule cgi_module modules/mod_cgi.so
为了更好的管理和监控mod_cgi
模块,mod_cgi
模块提供了三个指令用于配置mod_cgi
日志记录。
ScriptLog
指令- 设置
CGI
脚本错误信息的日志位置和名称,如果使用相对路径则以ServerRoot
作为参考路径 - 示例:
ScriptLog logs/cgi_log
- 设置
ScriptLogBuffer
指令- 设置日志记录的
put
或post
内容的大小,以防止日志增长过快,默认为1024
字节 - 示例:
ScriptLogBuffer 1024
- 设置日志记录的
ScriptLogLength
指令- 设置
CGI
脚本日志的大小 - 这个日志会记录所有的请求头、所有脚本输出信息,当记录信息超过了日志大小限制则不会再想日志内写入了
- 示例:
ScriptLogLength 10385760
- 设置
Apache
服务器提供了很多模块,这些模块通常都会带有与之相对应的处理器,Apache
会将不同的资源交给不同的处理器进行处理。当加载完CGI
模块后,用户可以使用由mod_cgi
模块提供的cgi-script
处理器来对所有的CGI
资源进行处理。所有,我们需要对CGI
进行定义,让CGI
资源使用cgi-script
来进行处理。
对于CGI
资源,常见的定义方法有三种:定义目录、定义请求、定义文件。
- 定义目录
- 使用
mod_alias
模块提供的ScriptAlias
指令来定义一个CGI
脚本的专用目录,访问这个目录内的任何文件的链接都会被当成对CGI
脚本的访问,因此需要进行严格的安全权限设置才可以保证CGI
的安全。 - 为了保证安全性,需要对
CGI
脚本的权限进行配置,使用专门的用户和组。
- 使用
# 示例一
# 访问http://192.168.1.100/cgi-bin/printenv地址,会在/usr/local/httpd-ssl/cgi-bin目录下查找printenv脚本,如果找到了会把它当做CGI脚本执行
ScriptAlias /cgi-bin/ "/usr/local/httpd-ssl/cgi-bin/"
# 示例二
# 除了可以在全局环境中定义整个目录为CGI目录外,还可以在特定的目录中启用CGI
# 还可以结合AddHandle指令来设置何种文件为CGI文件
<Directory /usr/local/apche2/htdocs/somedir>
Options +ExecCGI
</Directory>
- 定义请求
- 可以使用
ScriptAliasMatch
指令来进行定义,作用于ScriptAlias
一样,只是它可以使用正则表达式匹配用户请求 - 示例:
ScriptAliasMatch ^/cig-bin(.*) /usr/local/httpd-ssl/cgi-bin/$1
- 解释:匹配用户请求的
URL
路径,对于到服务器的目录下查找对应文件
- 可以使用
- 定义文件
- 将文件定义成
CGI
脚本,用户使用AddHandle
指令指定一种文件作为CGI
资源使用 - 只能用于目录容器中,无法将它作用于全局配置中。
- 示例:
AddHandler cgi-script .cgi .pl
- 解释:匹配以
.cgi
和.pl
结尾的文件,当成是CGI
脚本文件
- 将文件定义成
1.2 mod_cgid 模块
mod_cgid
模块与mod_cgi
模块类似,它除了多提供一个ScriptSock
指令外,当你选择了使用多线程模型的mpm
模块时,mod_cgid
会自己代替mod_cgi
进行工作。
ScriptSock
指令- 设置与
CGI
守护进程通信的套接字文件名前缀 - 我们可以需要设置一下这个文件的权限,只允许
root
访问
- 设置与
ScriptSock /var/run/cgid.sock
1.3 mod_actions 模块
通常定义CGI
的方式有定义目录、定义请求、定义文件这三种方法,但对于一些特殊的情况。例如,根据特定的媒体类型或请求方法,需要使用CGI
脚本,而提供这些方法就是mod_actions
模块,提供了两个指令:Action
指令和Script
指令。
Action 指令
- 可以对指定类型的文件使用特定的
CGI
脚本来进行处理
# 示例1
# 将所有的gif文件交由cgi-bin目录下的images.cgi的处理
Action image/gif /cgi-bin/images.cgi
# 示例2
# 先定义了一个文件类型.xyz,随后将这个文件类型交由program.cgi处理
AddHandler my-file-type .xyz
Action my-file-type /cgi-bin/program.cgi
# 示例3
# news目录会被强制使用news-handler处理器来进行处理
# 随后通过Action设置news-handler会被news.cgi处理,并通过virtual参数,关闭所有对于所请求的文件是否真实存在的检查
<Location /news>
SetHandler news-handler
Action news-handler /cgi-bin/news.cgi virtual
</Location>
Script 指令
- 可以在使用特定请求方法时运行
CGI
脚本
# 用户使用GET方式访问时会调用search脚本进行处理
# 但是这种处理也仅限制于收到查询参数时才会被处理,否则GET请求会被正常处理
# Script指令可以使用任意的请求方法,对大小写敏感
Script GET /cgi-bin/search
1.4 CGI 环境变量
CGI
的环境变量是CGI
于服务器之间交换信息的主要途径。
1.5 修改 CGI/SSI 环境变量
通常来说,对于
Apache
的环境变量时很少被修改的,这是因为大部分的CGI
变量都已经通过输入请求送入到CGI
脚本中,即使没有输入CGI
也可以获得一些变量信息。即便如此,Apache
还是提供mod_env
和mod_setenvif
模块用于设置CGI
、SSI
的环境变量。
mod_env 模块
- 用于控制向
CGI
脚本或SSI
页面输入的环境变量 - 可以使用
mod_env
模块提供的三个指定来修改、删除CGI
脚本或SSI
页面的环境变量 PassEnv
指令:指定一个或多个环境变量,并从Shell
环境传送给CGI
脚本SetEnv
指令:设置一个环境变量传送给CGI
脚本,如果这个变量不存在,则创建该变量UnsetEnv
指令:在传送到CGI
脚本与SSI
页面之前删除一个环境变量
mod_setenvif 模块
mod_setenvif
模块比mod_env
模块复杂点,允许根据请求的条件匹配指定的正则表达式来设置环境变量- 同时在
mod_setenvif
模块中,同样的指令排列的顺序不同也会产生不同的效果 BrowserMatch
指令:根据HTTP
头部的User-Agent
字段定义环境变量,可以使用正则表达式来指定它的第一个参数BrowserMatchNoCase
指令:与BrowserMatch
指令功能一样,只是区分大小写SetEnvIf
指令:根据当前HTTP
请求中的属性定义一个或多个环境变量- 首先指定一个
HTTP
请求头区域,如Host
、User-Agent
、Referer
等 - 而第二个参数则通常是一个
Perl
兼容的正则表达式,用来判断之前属性内容是否匹配,最后设置环境变量
- 首先指定一个
SetEnvIfNoCase
指令:与SetEnvIf
指令功能一样,只是区分大小写
# BrowserMatch
# 为Mozilla浏览器设置netscape头,而对于MSIE不设置netscape头
BrowserMatch ^Mozilla netscape
BrowserMatch MSIE !netscape
# SetEnvIf
# 如果Referer头表示来自www.mydomain.com,则设置intra_site_referral环境变量
SetEnvIf Referer www\.mydomain\.com intra_site_referral
2. FastCGI
CGI
技术是随着互联网的出现一同出现的技术,长期以来它一直是Web
服务器上通用的编程接口,但是这种技术在当初设置的时候显然并没有考虑到几十年之后的今天会遇到如此多的问题,如安全威胁、执行性能地下等。为了解决这个问题,应运而生了FastCGI
以取代CGI
技术。
使用FastCGI
只需要简单修改原有的CGI
脚本即可实现对CGI
而支持,同时还针对CGI
的执行性能地下做了专门的设置,FastCGI
模块在启用后长期驻留内存,只需要激活后即可使用,而不像CGI
一样每次启动时都需要fork
操作,从而极大提高了执行效率。
- FastCGI 工作流程
- FastCGI 的优点
FastCGI
独立于Web
服务器,FastCGI
的奔溃不会影响到Web
服务本身FastCGI
比传统的CGI
更加安全,提供了在独立进程中运行程序的能力- 更多的可扩展性,
FastCGI
除了可以完成HTTP
请求响应,还可以提供如模块化的身份验证和授权检查等 - 开始支持分布式计算,管理员可以在多台服务器上服务运行
FastCGI
程序,以分担Web
服务器的压力 - 性能更加出色,传统的
CGI
只能一个程序处理一个请求,而FastCGI
可以同时处理多个请求
FastCGI
的缺点主要是需要长期占用内存,如果你的访问很多或除了内存泄漏,时间一长就会占用很大的内存空间,而CGI
在执行完成后直接退出,所有不会出现这个问题。
目前在Apache
上实现FastCGI
由两种方式,这两种方式都是使用模块来实现的,但是他们的区别就像当年的apache-ssl
与mod_ssl
一样。一种方法是你可以使用由Apache
官方提供的mod_fcgid
模块,另一种方法则是使用http://www.fastcgi.com
上提供的mod_fastcgi
模块来实现。在Apache2.4
会将mod_fcgid
模块作为正式官方的fcgi
模块。
2.1 安装 mod_fcgid 模块
# 下载mod_fcgid模块
tar xf mod_fcgid-2.4.5.tar.gz && cd mod_fcgid.2.4.5/
# 配置mod_fcgid模块
APXS=/usr/local/httpd-ssl/bin/apxs ./configure.apxs
# 编译安装
make && make install
2.2 配置 mod_fcgid
现在只需要使用由mod_fcgid
源代码提供的一个小工具fixconf.sed
来进行调整,其实就是一个sed
的脚本,通过sed
程序对配置文件中旧的mod_fcgid
指令进行替换。
# 使用fixconf.sed脚本替换旧的mod_fcgid模块指令
./ fixconf.sed httpd.conf
- 设置 fcgid 支持 perl
# httpd.conf配置文件
<Directory /usr/local/apache/fcgi-bin/>
SetHandler fcgid-script
Options +ExecCGI
Order allow,deny
Allow from all
</Directory>
# 重启测试
apachectl restart
- 设置 fcgid 支持 PHP
fcgid
对PHP
的支持是通过PHP
所提供的php-cgi
程序来实现的,php-cgi
程序是一个FastCGI
管理器,可以通过fcgid
来对它进行调用。如果系统中安装了PHP
,但是没有php-cgi
程序,说明你的PHP
是以模块方式安装的,此时需要重新安装PHP
为CGI
方式。
# httpd.conf配置文件
FcgidMaxRequestsPerProcess 10000
Alias /phpapp/ /usr/local/phpapp/
AddHanler fcgid-script .php
Options +ExecCGI
FcgidWrapper /usr/local/bin/php-wrapper .php
Order allow,deny
Allow from all
# 在/usr/local/bin/目录下新建一个php-wrapper文件
#!/bin/sh
PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS
exec /usr/local/bin/php-cgi
chmod a+x /usr/local/bin/php-wrapper