简介
- 本文章主要介绍下,如何通过Nginx + fastCGI来部署动态网页。
CGI介绍
- 在介绍fastCGI之前先介绍下CGI是什么。
- CGI : Common Gateway Interface,公共网关接口。在物理层面上是一段程序,运行在服务器上,提供同客户端HTML页面的接口。
- Nginx+CGI处理步骤
- 用户发送HTTP请求到Web服务器
- Web服务器fork一个CGI子进程,将用户请求交给CGI程序
- CGI程序把处理结果传送给Web服务器,CGI子进程被销毁
- Web服务器把结果返回到用户
- CGI缺点
- CGI每处理一个请求,就要fork一个子进程,处理完请求,再销毁子进程。频繁的创建和销毁进程,就会大大降低Web服务器的效率。
- fastCGI
- fastCGI是对CGI的优化,fastCGI并不会每处理一个请求就创建一个进程, 这样就避免了频繁创建和销毁CGI进程,可以大大提高服务器的效率。
- 下面就重点介绍下fastCGI
fastCGI
- FastCGI是一个可伸缩的、高速的在HTTP服务器和动态脚本语言间通信的接口,主要优点是把动态语言和HTTP服务器分离开来。
- 主要是将CGI进程保持在内存中进行管理调度,以获得较高的性能。
- fastCGI的工作原理
- Web服务器启动时载入fastCGI进程管理器
- fastCGI进程管理器自身初始化,启动多个CGI子进程并等待来自Web服务器的连接
- 当客户端请求到达Web服务器时,fastCGI进程管理器选择并连接到一个CGI进程来处理请求
- fastCGI子进程完成处理后将结果返回给Web服务器
- 问题
- Nginx下fastCGI与服务器是分离的,就是Nginx无法直接调用fastCGI,需要用spawn-fcgi来管理
spawn-fcgi
- spawn-fcgi是Nginx和fastCGI之间的桥梁,负责Nginx和fastCGI之间的数据通信
安装
- fastCGI
- ./configure
- make
- make install
- 如果make时报错,在libfcgi/fcgio.cpp中添加头文件 #include <stdio.h>
- spawn-fcgi
- ./configure
- make
- make install
- 关于Nginx的安装另一篇文章中有介绍 : Nginx部署静态网页
环境配置
- Nginx配置
- 主要是将Nginx处理不了的指令交给fastCGI操作
- 打开Nginx配置文件 /usr/local/nginx/conf/nginx.conf,在server字段里加一个location字段
-
# 处理指令 location /fastCgiTest{ # 配置fastcgi模块,这里的端口是fastCGI进程的端口 fastcgi_pass 192.168.206.128:10010 # 包含配置文件 include fastcgi.conf }
-
- Nginx默认展示登录网页(用该程序替换Nginx默认index.html)
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>FastCGI测试网站</title> </head> <body> <h1 align="center">FastCGI测试网站</h1> <div class="container"> <form method="post" action="http://192.168.206.128/fastCgiTest"> <p align="center"><label>姓名:<input type="text" name="username" placeholder="admin" autofocus="autofocus"></label></p> <p align="center"><label>密码:<input type="tel" name="phone" placeholder="000" required="required"></label></p> <p align="center"> <button class="mybtn">登录</button> </p> </form> </div> </body> </html>
-
spawn-fcgi的使用
- 命令 : spawn-fcgi -a IP -p PORT -f fastcgi程序
- IP : Nginx服务器ip地址,就是上面配置的127.0.0.1
- PORT : 服务器将数据发送到的端口,就是上面我们配置的10010端口
- fastcgi程序 : spawn-fcgi fork fastcgi进程,fastcgi程序需要我们自己实现并编译。
编写fastcgi程序
- 这是参考fastcgi中的一个demo写的一个,主要实现登录功能,如果输入正确的用户名和密码,展示登录成功界面,如果输入错误的用户名和密码,继续展示登录界面,并提示重新登录。
-
#include "fcgi_config.h" #include <stdlib.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef _WIN32 #include <process.h> #else extern char **environ; #endif #include <string.h> #include "fcgi_stdio.h" //检查登录账号和密码 int checkLogin(char* recvBuf, const char* userName, const char* password); int main () { char **initialEnv = environ; int count = 0; while (FCGI_Accept() >= 0) { //请求数据长度 char *contentLength = getenv("CONTENT_LENGTH"); //请求方法(GET/POST) char *requestmechod = getenv("REQUEST_METHOD"); //响应头(printf相当于发送数据) printf("MyFlag: IsFastCGI\r\n"); //可以加自定义响应头 printf("Content-type: text/html\r\n"); printf("\r\n"); int length = 0; //POST请求 if(strcmp(requestmechod, "POST") == 0){ length = strtol(contentLength, NULL, 10); //post请求没有数据,不处理 if(length == 0){ continue; } //读取post请求数据 char ch; char recvBuf[1024 * 10] = {0}; for (int i = 0; i < length; i++) { if ((ch = getchar()) < 0) { printf("read post data failed\n"); continue; } recvBuf[i] = ch; } if(checkLogin(recvBuf, "admin", "000")){ printf("<h1>Login success!</h1>\r\n"); }else{ printf("<!DOCTYPE html>\r\n"); printf("<html lang=\"en\">\r\n"); printf("<head>\r\n"); printf("<meta charset=\"UTF-8\">\r\n"); printf("<title>FastCGI测试网站</title>\r\n"); printf("</head>\r\n"); printf("<body>\r\n"); printf("<h1 align=\"center\">FastCGI测试网站</h1>\r\n"); printf("<div class=\"container\">\r\n"); printf("<form method=\"post\" action=\"http://192.168.206.128/fastCgiTest\">\r\n"); printf("<p align=\"center\"><label>姓名:<input type=\"text\" name=\"username\" placeholder=\"admin\" autofocus=\"autofocus\"></label></p>\r\n"); printf("<p align=\"center\"><label>密码:<input type=\"password\" name=\"password\" placeholder=\"000\" required=\"required\"></label></p>\r\n"); printf("<p align=\"center\">\r\n"); printf("<button class=\"mybtn\">登录</button>\r\n"); printf("</p>\r\n"); printf("</form>\r\n"); printf("</div>\r\n"); printf("<dialog open>\r\n"); printf("<p>用户名或密码错误,请重新登录</p>\r\n"); printf("<form method=\"dialog\">\r\n"); printf("<button align=\"center\">确定</button>\r\n"); printf("</form>\r\n"); printf("</dialog>\r\n"); printf("</html>\r\n"); } } } /* while */ return 0; } int checkLogin(char* recvBuf, const char* userName, const char* password){ char* p = recvBuf; char* pUserName = strtok(p, "&"); char* pPassWord = strtok(NULL, "&"); char* pUserNameKey = strtok(pUserName, "="); char* pUserNameValue = strtok(NULL, "="); char* pPassWordKey = strtok(pPassWord, "="); char* pPassWordValue = strtok(NULL, "="); if(strcmp(pUserNameValue, userName) == 0 && strcmp(pPassWordValue, password) == 0){ return 1; } return 0; }
- 编译
- gcc echo.c -lfcgi
- 启动fastcgi
- spawn-fcgi -a 192.168.206.128 -p 10010 -f ./a.out
- 如果有以下报错,说明启动失败了。先直接启动下a.out看是什么报错
- spawn-fcgi: child exited with: 127
- 直接启动a.out,可以看到以下报错
- ./a.out: error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory
- 说明找不到库文件libfcgi.so,这个文件在这个目录下 /usr/local/lib
- 可以把这个目录加到 /etc/ld.so.conf文件中,执行sudo ldconfig
- 再重新启动fastcgi程序。注意a.out前面一定要加路径。
- 有以下打印说明启动成功了
- spawn-fcgi: child spawned successfully: PID: 26378
测试
- 首先我们在浏览器中访问Nginx,默认端口为80。然后会展示我们写的登录网页,在登录网页中输入用户名和密码后,点击提交,会发送POST请求到Nginx配置文件中配置的/fastCgiTest指令上。Nginx就会根据ip和端口将指令转发到fastCGI程序,fastCGI程序处理POST请求数据,如果用户名和密码正确,显示登录成功,如果用户名和密码错误,继续展示登录界面,并提示用户重新登录。
- 先访问Nginx,展示默认网页
- 输入正确的用户名和密码,fastCGI程序处理后展示登录成功界面
- 输入错误的用户名和密码,fastCGI程序处理后,重新展示登录界面,并提示重新登录