Nginx如何使用FastCGI_nginx 开启fastcgi_windsofchange的博客-程序员秘密

技术标签: Nginx  

一、CGI是什么:

关于CGI是什么,这篇文章已经讲的非常清楚:

《万法归宗----CGI》

下面简单概括一下关于CGI的基本概念:

CGI = Common Gateway Interface,“通用网关接口”:

(1)“通用”,几乎所有的语言都支持CGI,都可以拿来编写CGI程序;

(2)“网关”,更形象的叫法是“协议翻译机”。通常与网关输入输出两端通信使用的是不同的协议,比如一方是HTTP,另一方可能是其他协议,比如企业内部自定义的协议等;
CGI程序通常部署在Web服务器上(Nginx、Apache),Web服务器调用CGI程序;

(3)“接口”,接口,API。

什么是接口协议:

协议是什么自不必说,通信双方或多方共同遵守的约定。

但是协议也分很多种:

二级制协议 - - - TCP/IP,协议内容是某某某字节、某某某比特位是干嘛的;

字符协议 - - - HTTP,描述第一行是干嘛的,第二行是干嘛的,没固定长度,没固定格式,按字符关键字去匹配;

这两种都是“网络协议”,描述报文内容详细语义的协议。

但是接口协议不同,接口协议一般指的是进行交换的接口间需要遵从的通信方式和要求,例如USB、Type-C、HDMI等。

CGI是如何工作的:

CGI程序本质上是OS操作系统上的一个普通的可执行的应用程序,

CGI可以理解为Web服务进程(Nginx进程、Apache进程)与一个运行在服务器上的CGI进程之间的协议,CGI会把HTTP请求消息中的请求头(Header)设置成进程的环境变量,把HTTP请求的包体设置成标准输入STDIN,进程的标准输出设置成HTTP响应(包含响应头和体),即返回一个HTML。

所以,CGI就是 Web服务器进程(Nginx、Apache)与 CGI进程 交互 的接口,输入HTTP请求(头和体),返回HTTP响应(头和体)。

CGI与Web应用服务器(Server)有何区别:

Nginx收到客户端的HTTP请求后有几种处理方式,对于静态资源的请求可直接返回资源给客户端,那么何时需要转发请求给应用服务器(如Tomcat),何时需要转发请求给CGI?

CGI与应用服务器的最大区别是:

Nginx与应用服务器之间通信使用的是HTTP协议,与CGI通信使用的标准输入输出流。

也就是说,CGI计算后产生的结果,是可以直接使用printf()在客户端上打印出来的(使用的标准输出流STDOUT),这样就有一些web场景必须要使用CGI,例如leetcode、实验楼等类型的在线编译工具,用户输入一段代码后编译结果就能在页面上打印显示出来。

(至于CGI如何计算,这个需要开发者去编写CGI的业务代码。)


二、CGI的缺点与FastCGI的引出:

CGI有一大硬伤:

每次HTTP请求CGI,Web服务器都要启动一个新的进程去运行这个CGI程序(颇具Unix特色的 fork-and-excute)。
当用户量巨大时,这样的操作会严重拖慢Web服务器的性能。

因此引出FastCGI,即一个常驻的进程池,由调度器负责将传递来的CGI请求传递给进程处理。

所以,FastCGI即使常驻型的CGI。


三、在Nginx中如何使用FastCGI:

在这里插入图片描述

1. 安装FastCGI库:

下载安装包后解压安装:

./configure
make
make install

2. 安装spawn-fcgi:

./configure
make
cp  /src/spawn_fcgi  /usr/local/nginx/sbin    # 拷贝spawn_fcgi可执行程序到/nginx/sbin目录下

3. 编写一个FastCGI的测试小程序:

#include <stdio.h>
#include <fcgi_stdio.h>

int main() {
    
	while(FCGI_Accept() >= 0) {
    
		printf("Content-type: text/html\r\n");
		printf("\r\n");
		printf("<title>fast CGI Hello!</title>");
		printf("<h1>This is My CGI!</h1>");
		printf("Thank you, CGI.\n");
	}
}

编译生成可执行文件:

gcc cgi_test.c -o cgi_test -lfcgi                     //动态编译
gcc cgi_test.c -o cgi_test /usr/local/lib/libfcgi.a	  //静态编译

(本机电脑中有点问题,动态编译一直报错找不到libfcgi.so,解决方法是在fcgi.conf的配置文件中指定动态链接库的位置:动态编译解决方法

4. 使用 spawn-fcgi 工具启动 cgi_test 程序:

cgi_test从本质上说只是一个普通的Linux进程,单独的运行它(./cgi_test)不会起任何作用,因此需要借助spawn-fcgi 去指定 cgi_test 的监听IP地址和端口号。

cd /usr/local/sbin
./spawn-fcgi -a 127.0.0.1 -p 9002 -f /usr/local/cgi_test

spawn-fcgi指定cgi_test绑定IP地址127.0.0.1、监听端口号9002,启动程序的绝对路径所在的cgi_test。

启动成功后会打印提示:

spawn-fcgi: child spawned successfully: PID: 5432

注: spawn-fcgi命令的参数:

./spawn-fcgi -h   		# 查看所有参数,其中主要的有:

-f <path>				# filename of the fcgi-application
-a <address>			# bind to IPv4/IPv6 address
-p <port>				# bind to TCP port

5. 编写Nginx的配置文件:

worker_processes 1;

events {
	worker_connections 1024;
}

http {
	include mime.types;
	default_type application/octet-stream;

	server {
		listen 9000;
		
		location ~\ .cgi {
			fastcgi_pass 127.0.0.1:9002;
			fastcgi_index index.cgi;
			fastcgi_param SCRIPT_FILENAME cgi$fastcgi_script_name;
			include ../conf/fastcgi_params;
		}
	}
}

关于配置文件中配置项的含义:

fastcgi_pass :
	# 类似于proxy_pass,也是服务器代理的功能。
	# proxy_pass指示将HTTP请求转到upstream中,fastcgi_pass则指示将请求转给后面标注的IP地址端口

fastcgi_index  index.cgi :
	# 设置了fastcgi默认使用的脚本。就是当SCRIPT_FILENAME没有命中脚本的时候,使用的就是fastcgi_index设置的脚本。
	
fastcgi_params:
	# 设置fastcgi请求中的参数,具体设置的东西可以在$_SERVER中获取到

随后使用编写的配置文件,启动Nginx:

./sbin/nginx -c my_conf/my_conf.conf

如何实现FastCGI负载均衡:

http {
    upstream fastcgi_end {
		server 127.0.0.1:9002 weight = 2;
		server 127.0.0.1:9005 weight = 1;
	}

	server {
		listen 9000;
		location ~\ .cgi {
			fastcgi_pass fastcgi_end;
		}
	}
}

6. 最后,在浏览器中访问cgi资源进行验证:

http://127.0.0.1:9000/123.cgi

显示页面:

在这里插入图片描述

因为Nginx配置文件中的策略是凡是 “.cgi” 后缀结尾的请求一律转到CGI程序处理,所有浏览器中输入的URI可以是任意名字的CGI文件,例如 “123.cgi”。


Tips:

1. Nginx配置文件中的正则表达式:

http {
	server {
		location ~\ .cgi {

		}
	}

	server {
		location ~\ .(mp3|mp4) {

		}
	}
}

~\ .cgi表示客户端的HTTP请求中的URI凡是以 “.cgi” 结尾的文件,都转到这个本location指示的服务器资源上去;
~\ .(mp3|mp4)表示以 “.mp3” 或者 “.mp4” 后缀结尾的请求。

2. 网关和路由器的区别:

简而言之,连接两个网络的设备,都是网关。

网关是一个大的概念,不具体特指一类产品,只要连接两个不同网络的设备都可以叫网关,路由器可以实现网关的功能。所谓网关,可以是路由器、三层交换机、防火墙等。


遗留问题:

FastCGI内部的工作原理是什么?
CGI都提供哪些更高级的功能?如何编写一个更复杂的CGI程序?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ArtAndLife/article/details/110358105

智能推荐

Delphi2005的新特性_chenzhiya的博客-程序员秘密

Borland Delphi 2005 的启动画面1, 简介Borland Delphi 2005 是目前delphi的最新版本, 提供了在Microsoft Windows的操作系统和Microsoft .NET 框架 1.1 版本下的快速开发环境, 同时可用Delphi语言(适应win32和.NET 1.1)与C#(只能适应>NET 1.1)开发产品总览Delphi 2005 可以看成拥有

基本urllib库_普通网友的博客-程序员秘密

urlib库urllib库是Python中一个最基本的网络请求库。可以模拟浏览器的行为,向指定的服务器发送一个请求,并可以保存服务器返回的数据。urlopen函数:在Python3的urllib库中,所有和网络请求相关的方法,被集到url1ib.request横块下面了,以先来看下orlopen数基本的使用:fron urllib import request       ...

android动态加载so破解,[原创] 记一次so文件动态解密_weixin_39840733的博客-程序员秘密

写在前面整个程序基本上就是一个 动态注册 + so函数加密 的逻辑,中间加了一些parser的东西主要考察了elf文件结构的一些知识以及在攻防对抗中防止IDA静态分析的姿势题目描述找到flagWriteUp360加固,先脱壳,看入口函数MainActivity具体的逻辑写到so里了,使用IDA打开so文件,先看有没有.init和.init_array,发现只有.init_array节,跟进去一看又...

Lua教程:Lua调用C/C++函数(4)_tianxiawuzhei的博客-程序员秘密

Lua教程:Lua调用C/C++函数(4)JUL 30TH, 2014 12:04 PM前言示例一定义C++函数指针注册此函数给LuaLua里面调用此函数示例二定义C++函数注册此Lua函数在Lua里调用此函数实现一个Lua模块结语推荐阅读本教程将介绍如何在Lua里面调用c/c++函数。

随便推点

全国地区对应身份证号码值关系--身份证号前2位_花言简的博客-程序员秘密

省份 对应身份证前两位 北京市 11 天津市 12 河北省 13 山西省 14 内蒙古自治区 15 辽宁省 21 吉林省 22 黑龙江省 23 上海市 31 江苏省 32 浙江省 33 安徽省 34 福建省 35 江西省 36 山东省 37 ...

Gradle使用maven仓库,而不使用gradle仓库_这瓜保熟么的博客-程序员秘密

1:找的maven仓库的位置复制路径E:\repository,由于我是使用idea设置的maven仓库位置,2:配置环境变量GRADLE_USER_HOME 将上面的E:\repository配置进去3:重启idea验证  是否生效 可以看到Gradle模块的Service directory path变成了我们设置的GRADLE_USER_HOME环境的变量的位置,说明grad...

【BZOJ】2555: SubString(后缀自动机)_aocong4527的博客-程序员秘密

http://www.lydsy.com/JudgeOnline/problem.php?id=2555学到了如何快速维护right值orz(不过这仍然是暴力维护,可以卡到O(n)首先我们在加一个新节点的时候直接遍历它的parent树就行啦啦!!!!这样直接就暴力维护了。。。我竟然没想到。。然后在复制新节点的时候不要忘记将right也要赋值进去。。然后就是裸题了...

Encryption Technology_yangzhenping的博客-程序员秘密

Encryption Technology1.Encryption technology is the most common security ways, the key of data encryption technology is:encryption/decryption algorithm and key management.2.The basic process of data encryption is to process the original plaintext file or d

【计算几何】线段相交_成长的小牛233的博客-程序员秘密

问题描述:已知两条线段P1P2和Q1Q2,判断P1P2和Q1Q2是否相交,若相交,求出交点。两条线段的位置关系可以分为三类:有重合部分、无重合部分但有交点、无交点。算法的步骤如下:1.快速排斥实验。设以线段P1P2为对角线的矩形为R,设以线段Q1Q2为对角线的矩形为T,如果R和T不相交,则两线段不相交。2.跨立实验。如果两线段相交,则两线段必然相互跨立对方。若P1P2跨

微信小程序(5)-新闻页面制作(1)_芭乐视频_芭乐_0916的博客-程序员秘密

制作如图所示新闻页面(newspage)之导航栏步骤如下:(1)在newspage.js中定义数据(数据都放在.js中的data内)data: {  newsTitles:['要闻','国际','国内','娱乐','体育','科技','视频']}(2)在newspage.wxml中定义显示(视图层)     "{{newsTitles}}" data-i

推荐文章

热门文章

相关标签