#一、简述 Nginx支持使用FastCGI。它与CGI的区别在于,不需要重复启动CGI进程,从而节省了创建进程和结束进程的开销,避免了不必要的开销,提高了效率。
具体关于CGI和FastCGI的原理和运行流程请请参考这篇文章。
#二、开发环境 | 名称 | 版本 | |:------------: | :---------------------------------: | | 操作系统 | Ubuntu Server 12.04 64bit | | Nginx | 1.2.9 | | spawn-fcgi | 1.6.4 | | libfcgi | 最新版 |
其中spawn-fcgi是FastCGI的管理程序,负责启动FastCGI并创建和Nginx的连接。libfcgi是方便FastCGI开发的工具包。
接下來的操作都一样,解压源代码,./configure,make,make install,注意install的时候要有root权限。貌似libfcgi的源代码网站关闭了,所以建议使用二进制方法安装。在Ubuntu上直接apt-get:
sudo apt-get update
sudo apt-get install libfcgi-dev
#三、一个简单的例子:Hello World! ##1、功能 下面通过一个简单的FastCGI的实例来介绍开发过程,这个FastCGI接收用户的请求,然后向用户返回Hello World! 和用户请求的次数,以及请求中带有的参数。
##2、代码结构 FastCGI的代码结构应该是:对所需的资源进行初始化,然后在一个循环里不停的使用FCGI_Accept()
等待请求,然后处理请求,输出响应。FastCGI比CGI高效的地方就体现在这里,用伪代码表示如下:
#include <fcgi_stdio.h>
int main() {
初始化操作
while(FCGI_Accept() >= 0) {
处理请求
输出响应
}
return 0;
}
FCGI_Accept()
从HTTP服务器接收一个请求,并且为请求创建一个与CGI兼容的运行环境(execution environment)。
如果程序当做CGI被调用,则第一次调研FCGI_Accept()
函数是一个空操作(no-op),再次调用则会返回-1。这样做就可以使得正确编码的FastCGI程序(即按照上面结构来编码)只处理一个请求然后退出,表现的就像CGI程序一样。
如果程序当错FastCGI被调用,则首次调用FCGI_Accept()
函数表示程序已经完成了初始化操作并准备好接收第一个请求了。接下来再调用FCGI_Accept()
表示程序已经处理完了当前的请求并准备好接收一个新的请求。程序可以调用FCGI_Finish()
来表示处理完了当前的请求,但是不接受新的请求。一段时间后,程序准备好再次接收新的请求时,可以再调用FCGI_Accept()
。
有关FCGI_Accept()和FCGI_Finish()的具体用法请参考Man Page: FCGI_Accept(), FCGI_Finish()。 中文翻译: FCGI_Accept(), FCGI_Finish()。
##3、获取请求中的参数 FastCGI通过环境变量来传递请求的相关数据,具体内容如下表(内容来自CGI101):
环境变数 | 说明 |
DOCUMENT_ROOT | The root directory of your server |
HTTP_COOKIE | The visitor's cookie, if one is set |
HTTP_HOST | The hostname of the page being attempted |
HTTP_REFERER | The URL of the page that called your program |
HTTP_USER_AGENT | The browser type of the visitor |
HTTPS | "on" if the program is being called through a secure server |
PATH | The system path your server is running under |
QUERY_STRING | The query string |
REMOTE_ADDR | The IP address of the visitor |
REMOTE_HOST | The hostname of the visitor |
REMOTE_PORT | The port the visitor is connected to on the web server |
REMOTE_USER | The visitor's username (for .htaccess-protected pages) |
REQUEST_METHOD | GET or POST |
REQUEST_URI | The interpreted pathname of the requested document or CGI (relative to the document root) |
SCRIPT_FILENAME | The full pathname of the current CGI |
SCRIPT_NAME | The interpreted pathname of the current CGI (relative to the document root) |
SERVER_ADMIN | The email address for your server's webmaster |
SERVER_NAME | Your server's fully qualified domain name (e.g. www.cgi101.com) |
SERVER_PORT | The port number your server is listening on |
SERVER_SOFTWARE | The server software you're using (e.g. Apache 1.3) |
##4、代码
#include <fcgi_stdio.h>
#include <stdlib.h>
int main() {
unsigned int req_count = 0;
while(FCGI_Accept() >= 0) {
FCGI_printf("Content-type: text/html\r\n\r\n");
FCGI_printf("<title>Hello World!</title>"
"<h1>Hello World!</h1>");
FCGI_printf("<h2>request times: %u</h2>", ++req_count);
FCGI_printf("QUERY_STRING: %s</br>", getenv("QUERY_STRING"));
FCGI_printf("REMOTE_ADDR: %s</br>", getenv("REMOTE_ADDR"));
}
return 0;
}
注意一点,输出内容必须带有\r\n
把响应的头部和正文分开,响应的头部可以为空,但是\r\n
不可以省略。否则Nginx会出现Error页面。
##5、编译 编译时记得添加-lfcgi
选项表示要链接libfcgi库。
$ g++ -W hello_fcgi.cpp -o hello_fcgi -lfcgi
#四、使用FastCGI ##1、修改Nginx配置文件 首先需要修改一下Nginx的配置文件nginx.conf
,指定使用FastCGI的地方。比如我们想让所有访问/fcgi
这个路径的请求都交给hello_fcgi程序处理,那么就在server
块中添加如下内容:
location /fcgi {
fastcgi_pass 127.0.0.1:8000;
fastcgi_index index.cgi;
include fastcgi.conf;
}
这段内容告诉Nginx处理访问/fcgi路径的请求的规则,以及FastCGI管理器的IP和端口号和一些其他配置,Nginx收到请求后会把请求转发给这个地址,然后会重定向到FastCGI程序。 通知Nginx重新读取配置文件:
$ sudo /usr/local/nginx/sbin/nginx -s reload
##2、使用FastCGI管理器启动FastCGI程序 现在使用之前安装的spawn-fcgi来启动刚才编写的FastCGI程序:
$ spawn-fcgi -p 8081 -f ./hello_fcgi
其中-p
选项指定绑定的端口号,还可以使用-a
选项指定绑定的ip地址,注意这里的IP和端口号要和nginx.conf
中配置的匹配。-f
选项指定FastCGI程序的位置。spawn-fcgi的更多用法可以使用-h
参数来查看。正常情况下成功启动后spawn-fcgi会提示如下信息:
spawn-fcgi: child spawned successfully: PID: 52825
##3、效果 现在可以使用浏览器访问Nginx服务器的/fcgi
路径查看效果了: