FastCGI 是对现有 CGI(Common Gateway Interface,公共网关接口)的增强,CGI 是一种连接外部应用程序与 Web Server 的标准。与 CGI 一样,FastCGI 应用程序在单独、隔离的进程中运行。以下是使用 FastCGI 的一些优点:
使应用程序在客户机请求之间持久化、消除应用程序启动开销以及允许应用程序在客户机调用之间保持状态。
使应用程序驻留在远程系统(不同于正在运行 Web Server 的系统)上。
使应用程序功能更加灵活,并显式支持进行客户机验证和输入过滤的应用程序。
允许管理员限制 FastCGI 服务器对系统所产生的影响。
通过使用 FastCGI 插件,Web Server 能够以可伸缩的方式安全地使用流行的第三方动态内容生成技术(如 Perl 和 Python)。
有关 FastCGI 的更多信息,请参阅 http://www.fastcgi.com/devkit/doc/fcgi-spec.html 中的规范。
FastCGI 插件提供以下服务器应用程序函数 (Server Application Function, SAF):
以下各节介绍了 FastCGI SAF 的各种参数和“错误原因”字符串:
auth-fastcgi 是修补程序检查函数。此函数用于将请求转发到“授权者”FastCGI 应用程序。如果授权成功,则发送返回码 200。否则,将“授权者”FastCGI 应用程序的响应发送回至用户代理。
可以在 http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S6 中找到有关 FastCGI 角色的更多信息。
以下位置提供了 auth-fastcgi SAF 接受的参数:FastCGI SAF 参数。
以下 obj.conf 代码示例说明了 auth-fastcgi 的用法:
PathCheck fn="auth-fastcgi" app-path="/usr/bin/perl" app-args="/fastcgi/apps/auth/SimpleAuth.pl" bind-path="localhost:3432"。
responder-fastcgi 是服务函数。此函数用于将请求转发到充当“响应者”的 FastCGI 应用程序。“响应者”应用程序的响应将被发送到用户代理。http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S6 中提供了有关 FastCGI 角色的更多信息。
以下位置提供了 responder-fastcgi SAF 接受的参数列表:FastCGI SAF 参数。
以下 obj.conf 代码示例说明了 responder-fastcgi 的用法:
Service fn="responder-fastcgi" app-path="/fastcgi-enabled-php-installation/bin/php" bind-path="localhost:3433" app-env="PHP_FCGI_CHILDREN=8" app-env="PHP_FCGI_MAX_REQUEST=500"。
filter-fastcgi 是服务函数。此函数用于将请求转发到“过滤器”类型的 FastCGI 应用程序。“过滤器”应用程序接收与 HTTP 请求关联的信息,还接收存储在服务器上的文件中的数据。然后,“过滤器”应用程序生成“已过滤”版本的数据流作为响应。该响应将被发送到用户代理。http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S6 中提供了有关 FastCGI 角色的更多信息。
以下位置提供了 filter-fastcgi SAF 接受的参数列表:FastCGI SAF 参数。
以下 obj.conf 代码示例说明了 filter-fastcgi 的用法:
Service fn="filter-fastcgi" app-path="/fastcgi/apps/filter/SimpleFilter" bind-path="localhost:3434" app-env="LD_LIBRARY_PATH=/fastcgi/fcgi-2.4/libfcgi/.libs" min-procs=2
error-fastcgi 是错误函数。error-fastcgi SAF 处理特定于 FastCGI 插件的错误。但是,此函数不处理 HTTP 错误。发生错误时,可以将 FastCGI 插件配置为显示特定的页面或将请求重定向至特定的 URL。
以下位置提供了 error-fastcgi SAF 接受的参数列表:FastCGI SAF 参数。
以下 obj.conf 代码片段说明了 error-fastcgi 的用法:
Error fn="error-fastcgi" error-reason="Invalid Parameters" error-url="http://www.foo.com/errorPage.html"
有关 error-fastcgi 参数的信息,请参见FastCGI SAF 参数。
FastCGI 插件 SAF "auth-fastcgi"、" responder-fastcgi" 和 "filter-fastcgi" 全都接受下列参数,除非另外显式说明:
请注意,参数 chroot、user、group 和 nice 只适用于 UNIX 平台。在 Windows 平台上,这些参数都将被忽略。
app-path-(可选)处理请求的 FastCGI 应用程序路径。该功能依赖于 bind-path 参数的值,如下所示:
如果仅指定了 app-path,插件将创建 FastCGI 应用程序,该应用程序侦听由插件创建的 UNIX 域套接字。然而,仅 UNIX 平台接受此参数。在 Windows 上将记录错误消息。
如果同时指定了 app-path 和 bind-path 参数,插件将启动指定的 FastCGI 应用程序进程并将它们绑定到指定的 bind-path。
如果仅指定了 bind-path,则 FastCGI 应用程序将被认为正在远程运行。因此,插件将不启动 FastCGI 应用程序进程。
如果既未指定 "app-path",也未指定 "bind-path",则插件将记录错误消息。
app-args-(可选)作为参数传递至 FastCGI 应用程序进程的值。允许使用多个 app-args 参数。多个 app-args 参数的格式为 app-args="value" app-args="value" ..。
bind-path-(可选)可以是 Unix 域套接字名称或者是格式 "host:port"。"app-path" 参数的说明解释了 "bind-path" 参数的用法。请注意,Unix 域套接字名称仅适用于 UNIX 平台。在 Windows 平台上,必须将 bind-path 指定为 "host:port"。
min-procs -(可选)一个整数,用来指定要创建的 FastCGI 应用程序进程的最小数目。默认值为 1。
max-procs-(可选)一个整数,用来指定随时可以创建的 FastCGI 应用程序进程的最大数目。该整数值必须等于或大于 min-procs。默认值为 1。
chroot-(可选)用于设置 chroot FastCGI 服务器应用程序进程的根目录。默认值为 Web Server 的根目录。
user-(可选)指定用来运行 FastCGI 应用程序的用户 ID。默认值为 Web Server 的用户 ID。
group-(可选)FastCGI 应用程序将在指定的组下运行。默认值为 Web Server 的组。
nice-(可选)指定 FastCGI 应用程序进程的 nice/priority 值。
listen-queue-(可选)一个整数,用来指定套接字的侦听队列大小。此参数的默认值为 256。
app-env-(可选)作为环境变量传递到 FastCGI 应用程序进程的值对。允许使用多个 "app-env" 参数。多个 app-env 参数的格式为 app-env="name=value" app-env="name=value"....。
reuse-connection-(可选)一个布尔值,用来确定是否重复使用 FastCGI 应用程序连接。False(0、false 或 no)表示在每个请求后将关闭到 FastCGI 应用程序的连接。True(1、true 或 yes)表示对新请求重复使用现有连接。默认值为 false。另请参见 connection-timeout。
connection-timeout-(可选)如果 "reuse-connection" 被设置为 True,则此值指定池化连接的超时值(以秒为单位)。如果连接在指定的时间段内处于空闲状态,则插件将关闭该连接。此参数的默认值为 5 秒。另请参见 reuse-connection。
resp-timeout-(可选)一个整数,用来表示 FastCGI 服务器响应超时(以秒为单位)。如果在指定时间段内 FastCGI 应用程序未响应,将放弃请求。此参数的默认值为 5 分钟。
restart-interval-(可选)一个整数,用来表示两次重新启动 FastCGI 应用程序之间的时间间隔(以分钟为单位)。此参数的默认值为 60 分钟(1 小时)。如果将此参数的值设置为零,则不会强制重新启动 FastCGI 应用程序。
req-retry-(可选)一个整数,用来表示在 FastCGI 应用程序拒绝请求时插件应重新发送该请求的次数。此参数的默认值为零。
error-fastcgi 服务器应用程序函数 (Server Application Function, SAF) 接受以下参数:
error-url-指定在出现故障或错误时显示的页面、URI 或 URL。此参数的值可以为绝对路径、相对于文档根目录的路径、URL 或 URI。
error-reason-(可选)表示 FastCGI 协议错误的字符串。此字符串用来在发生任何插件错误时区分要显示的错误 URL。
本节提供了所有有效“错误原因”字符串及其说明:
“缺少配置参数或配置参数无效”:每当未指定 app-path 和 bind-path 时显示此字符串。
“存根启动错误”:启动 Fastcgisub 进程失败。
“存根连接失败”:无法连接至 Fastcgistub。
“没有权限”:FastCGI 应用程序或 Fastcgisub 没有执行权限。
“存根请求处理错误”:无法将请求发送至存根、存根针对请求发出的响应无效或未响应等。
“设置参数失败”:设置用户、组、Chroot、Nice 等失败。
“用户和/或组无效”:用户或组无效时显示此字符串。
“创建服务器进程失败”:FastCGI 应用程序执行失败或 FastCGI 应用程序无法绑定到指定的地址。
“Fastcgi 协议错误”:FastCGI 应用程序包含具有无效 FastCGI 版本或角色的标头。
“内部错误”:无法打开要发送至过滤器应用程序的文件或任何其他未知错误。
FastCGI 插件与 Web Server 7.0 捆绑在一起。该插件安装在以下位置:
32 位 FastCGI 插件二进制文件安装在 <install_dir>/plugins/fastcgi 目录中。 |
64 位 Solaris SPARC FastCGI 插件二进制文件安装在 <install_dir>/lib/plugins/fastcgi/64 目录中。 |
将安装以下 FastCGI 二进制文件:
libfastcgi.so(适用于 Solaris/Linux) |
fastcgi.dll(适用于 Windows) |
Fastcgistub.exe(适用于 Windows) |
libfastcgi.sl(适用于 HP-UX) |
Fastcgistub(可执行文件) |
可以使用位于 <instance-dir>/config 目录中的 Web Server 配置文件来配置 FastCGI 插件。要配置 FastCGI 插件,请执行以下步骤:
使用 "load-modules" 初始化函数加载 FastCGI 插件共享库。
Init fn=flex-init access="access" format.access="%Ses->client.ip% - %Req->vars.auth-user% [%SYSDATE%] \"%Req->reqpb.clf-request%\" %Req->srvhdrs.clf-status% %Req->srvhdrs.content-length%" Init fn="load-modules" shlib="libJava EEplugin.so" shlib_flags="(global|now)" Init fn="load-modules" shlib="libfastcgi.so" shlib_flags="(global|now)"
编辑 mime.types 文件以指定 MIME 映射。修改 MIME 类型映射为可选步骤。
例如,
#--Sun Microsystems Inc. MIME Information # Do not delete the above line. It is used to identify the file type. # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # type=application/octet-stream exts=bin type=application/astound exts=asd,asn ... ... type=magnus-internal/fastcgi exts=php ... ...
编辑 obj.conf 文件以使用前面几节中介绍的插件 SAF 配置特定于 FastCGI 的请求。
以下是修改的 obj.conf 文件示例:
# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # You can edit this file, but comments and formatting changes # might be lost when you use the administration GUI or CLI. <object name = "default"> AuthTrans fn="match-browser" browser="*MSIE*" ssl-unclean-shutdown="true" NameTrans fn="ntrans-Java EE" name="Java EE" NameTrans fn="pfx2dir" from="/mc-icons" dir="/ws7/lib/icons" name="es-internal" NameTrans fn="assign-name" from="/fcgi/*" name="fcgi.config" </object> <Object name="fcgi.config"> AuthTrans fn="auth-fastcgi" app-path="/fastcgi/apps/c/simpleAuth" bind-path="localhost:2111" Service fn="responder-fastcgi" app-path="/fastcgi_enabled_php_installation_dir/bin/php" app-env="name1=abc" </object> ...
请注意,通过为不同 URL 模式定义不同对象或将 SAF 映射至不同 MIME 类型,可以采用不同方法调用 FastCGI SAF。
有关 obj.conf 配置和语法的更多信息,请参阅管理配置文件参考指南。
Fastcgistub 是一个管理 FastCGI 应用程序进程生命周期的进程管理器。Fastcgistub 将消息记录在 Web Server 临时目录下的 Fastcgistub.log 文件中。如果发生任何错误,检查此文件可以帮助调试问题。
问题:未满足 FastCGI 请求
可能的原因和解决方法如下:
检查是否加载了 FastCGI 插件。如果在 Web Server 启动过程中显示以下消息,则表示已成功加载该插件。否则,请在 magnus.conf 中检查插件库的路径: FCGI1000: Sun Java System Web Server 7.0 FastCGI NSAPI Plugin < build info>
检查是否在 obj.conf 中正确指定了请求映射。有关 obj.conf 文件的更多信息,请参见 Sun Java System Web Server 管理员配置参考文件。
检查错误日志以找出任何可能的错误消息。
检查存根二进制文件和 FastCGI 应用程序的权限。如果未授予插件足够的权限,则插件将无法启动存根或应用程序。
检查 Fastcgistub.log 文件以找出存根端任何可能的错误。
如果可能的话,以单机模式运行 FastCGI 应用程序并检查它在运行时是否出现任何问题。
如果抛出任何与库相关的错误,请在 obj.conf 中将 LD_LIBRARY_PATH 指定为具有 LD_LIBRARY_PATH=<dependency library paths> 值的 app-env 参数。
问题:FastCGI 应用程序无法启动。
可能的原因和解决方法如下:
检查 Fastcgistub.log 文件以找出以下日志消息: |
.. <pid> process startup failure, trying to restart ... Even after trying <n> time(s), <application path> process failed to start...no more retries
启动失败的原因之一可能是加载相关库失败。可以通过将相应的库路径指定为 obj.conf 文件中配置的 FastCGI 应用程序的 app-env 参数值来解决此问题。例如:
Service fn="responder_fastcgi" app-path="/fastcgi/c/tux-app" bind-path="localhost:2112" app-env="LD_LIBRARY_PATH=/tuxedo/lib" |
可以使用 Perl、PHP、C 和 Java 开发 FastCGI 应用程序。以下各节简要介绍了使用几种常见编程语言开发此类应用程序的过程。
典型的 FastCGI 应用程序具有以下代码结构:
Initialization code Start of response loop body of response loop End of response loop
初始化代码只在应用程序初始化时运行一次。初始化代码执行的操作通常比较耗时,例如打开数据库或计算表或位图的值。将 CGI 程序转换为 FastCGI 程序的主要任务是将初始化代码与需要针对每个请求运行的代码分开。
响应循环连续运行,等待客户机请求到达。该循环以对 FCGI_Accept(FastCGI 库中的一个例程)的调用开始。FCGI_Accept 例程将阻止程序执行,直到客户机请求 FastCGI 应用程序为止。客户机请求到达后,FCGI_Accept 将解除阻止并运行一次响应循环主体,然后重新阻止,等待另一个客户机请求。只有在系统管理员或 Web Server 中止 FastCGI 应用程序时,该循环才会终止。
从 CPAN 下载并安装最新的 FCGI 模块。对于 ActivePerl,可以从 http://aspn.activestate.com/ASPN/Downloads/ActivePerl/PPM/Zips 下载模块。
有关使用 Perl 编写 FastCGI 应用程序的更多信息,请访问 http://www.fastcgi.com/devkit/fastcgi-prog-guide/ch3perl.htm#3659。
从 PHP 4.3.0 开始,FastCGI 成为 PHP 引擎支持的配置。要编译支持 FastCGI 的 PHP 4.3.x 或更高版本的引擎,请在构建进程中包括配置开关 --enable-fastcgi,例如:
./configure <other-options> --enable-fastcgi gmake |
编译完成后,php 二进制文件将启用 FastCGI。
使用 PHP 版本 5.1.2 或早期版本(包括 PHP 4.x)时,应配置 FastCGI 插件且 bind-path 的格式为“主机:端口”。例如,bind-path = "localhost:3333"。
对于 PHP 版本 5.1.3 和更高版本,bind-path 是可选的。如果指定了此项,其格式应为“主机:端口”。它可以是字符串。例如,bind-path = "myphpbindpath"。
FastCGI 开发工具包提供了用于编写 FastCGI C/Java 应用程序的 API。您可以从 http://www.fastcgi.com/devkit/doc/fcgi-devel-kit.htm 下载该工具包。
要构建下载的 FastCGI 开发工具包,请执行以下步骤:
有关使用 C 编写 FastCGI 应用程序的更多信息,请访问 http://www.fastcgi.com/devkit/doc/fcgi-devel-kit.htm#S3
有关使用 Java 编写 FastCGI 应用程序的更多信息,请访问 http://www.fastcgi.com/devkit/doc/fcgi-java.htm
本节包含使用 PHP、Perl 和 C 编写的 FastCGI 应用程序样例。
<?php $dir = "/tmp/"; // Open a known directory, and proceed to read its contents if (is_dir($dir)) { if ($dh = opendir($dir)) { while (($file = readdir($dh)) !== false) { echo "filename: $file : filetype: " . filetype($dir . $file) . "\n"; } closedir($dh); } } ?>
以上示例的 obj.conf 代码片段为:
<Object name="default"> NameTrans fn="assign-name" from="/fcgi/*" name="responder.fcgi" </Object> <Object name="responder.fcgi"> Service fn="responder-fastcgi" app-path="/foo/fastcgi-enabled-php-installation/bin/php" bind-path="localhost:3431" min-procs=3 </Object>
#!/usr/bin/perl use FCGI; while (FCGI::accept >= 0) { if( $ENV{'HTTP_AUTHORIZATION'} ) { # This value can be further decoded to get the actual username and password and then # perform some kind of user validation. This program only checks for the presence of # of this environment param and is not really bothered about its value print( "Status: 200\r\n" ); print( "\r\n" ); } else { print( "Status: 401\r\n" ); print( "WWW-Authenticate: basic realm=\"foo\"\r\n" ); print( "\r\n" ); } } Example obj.conf settings for the above example:
以上示例的 obj.conf 代码片段为:
<Object name="responder.fcgi"> AuthTrans fn="auth-fastcgi" app-path="/fastcgi/apps/auth/SimpleAuth.pl" bind-path="localhost:3432" Service fn="responder-fastcgi" app-path="/foo/fastcgi-enabled-php-installation/bin/php" bind-path="localhost:3433" app-env="PHP_FCGI_CHILDREN=8" min-procs=1 </Object>
第一次请求 http://localhost/fcgi/php/ListDir.php 时,浏览器将显示验证对话框。在用户输入用户名和密码后,将列出 "/tmp" 目录的内容。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcgi_stdio.h> void main(void) { size_t PageSize = 1024 * 3; char *page; FCGX_Stream *in, *out, *err; FCGX_ParamArray envp; int count=0; page = (char *)malloc(PageSize); if (page == NULL) { printf("Content-type: text/x-server-parsed-html\r\n"); printf("<title>malloc failure</title>"); printf("<h1>Cannot allocate memory to run filter. exiting</h1>"); printf("\r\n\r\n"); exit(2); } while(FCGI_Accept() >= 0) { char *tmp; char *execcgi; char *dataLenStr = NULL; int numchars = 0; int stdinDataSize = 0; int filterDataLen = 0; int dataToBeRead = 0; int x = 0; int loopCount = 0; count++; dataLenStr = getenv("FCGI_DATA_LENGTH"); if(dataLenStr) filterDataLen = atoi(dataLenStr); /* clear out stdin */ while (EOF != getc(stdin)) { stdinDataSize++; } dataToBeRead = filterDataLen; FCGI_StartFilterData(); tmp = page; /** just in case fread or fwrite moves our pointer **/ //start responding printf("Content-type: text/plain\r\n"); printf("\r\n"); /** send a new line at the beginning **/ printf("<title>SIMPLE FILTER</title>"); printf(<h1>This page was Filtered by SimpleFilter FastCGI filter</h1>"); printf("file size=%d<br>", filterDatalen); printf("stdin size=%d<br>, stdinDataSize); while(dataToBeRead > 0 ) { x = 0; page = tmp; if(dataToBeRead > PageSize) x = PageSize; else x = dataToBeRead; numchars = fread((void *)(page), 1, x, stdin); if( numchars == 0 ) continue; /** at this point your data is in page pointer, so do whatever you want with it before sending it back to the server. In this example, no data is manipulated. Only the count of number of times the filter data is read and the total bytes read at the end of every loop is printed. **/ dataToBeRead -= numchars; loopCount++; printf("loop count = %d ... so far read %d bytes <br>", loopCount, (filterDatalen - dataToBeRead)); } printf("\r\n\r\n"); /** send a new line at the end of transfer **/ fflush(stdout); page = tmp; /** restore page pointer **/ memset(page,NULL,numchars); } free(page); }
以上示例的 obj.conf 设置示例。
如果该 FastCGI 应用程序是在运行 Web Server 的计算机上运行,则
<Object name=<"filter.fcgi"> Service fn="filter-fastcgi" app-path="/fastcgi/apps/filter/SimpleFilter.exe" bind-path="localhost:3434" app-env="LD_LIBRARY_PATH=/fastcgi/fcgi-2.4/libfcgi/.libs" </Object>
如果该应用程序正在远程计算机上运行,则必须在 obj.conf 文件中包含以下代码行:
<Object name="filter.fcgi"> Service fn="filter-fastcgi" bind-path="<remote-host>:<remote-port>" </Object>
如果要过滤 Web Server 实例根目录下的 fcgi 目录中大小为 "26868" 字节的 "FilterThisFile" 文件,则对 "http://localhost/fcgi/filter/FilterThisFile" 的请求将生成以下输出:
This page was Filtered by SimpleFilter FastCGI filter
file size = 26868 |
stdin size = 0 |
loop count = 1... so far read 3072 bytes |
loop count = 2... so far read 6144 bytes |
loop count = 3... so far read 9216 bytes |
loop count = 4... so far read 12288 bytes |
loop count = 5... so far read 15360 bytes |
loop count = 6... so far read 18432 bytes |
loop count = 7... so far read 21504 bytes |
loop count = 8... so far read 24576 bytes |
loop count = 9... so far read 26868 bytes |