CGI调研
CGI(Common Gateway Interface,通用网关接口),是web服务器和服务器端应用程序(用来扩展服务器的功能)之间的一个协议。通过CGI接口,web服务器可以获取客户端提交的信息,转交给服务器端CGI程序进行处理,并将结果返回给客户端。这样就使得服务器端具有了与用户进行交互的能力。
通用,表示该协议不受客户机和服务器所运行的操作系统平台的限制;同时目前绝大多数的编程语言都支持CGI程序的编写。理论上来说,所有支持标准输入、标准输出,支持获取环境变量的编程语言都可以用来编写CGI程序,例如Perl、C/C++、Java、php、python……
网关,可以解释为“协议翻译机”,通常两端通信使用不同的协议。CGI可被用来作为HTTP服务器与其他第三方应用程序(CGI程序)之间的“连接件”或“中间件”。
接口,CGI可以为HTTP服务器与其他应用程序提供数据传输接口,也就是说互相之间有数据的输入和输出,而且数据传输遵循了一定的规则。
一、CGI的产生背景:
古早时期的Web服务器,只能响应客户端浏览器发来的HTTP静态资源的请求,根据URL中的路径信息查找服务器中存储的静态资源,如果资源存在,则返回给浏览器,用户看到的就是静态网页。
但是随着Web技术的发展以及大众要求的提高,逐渐出现了动态技术,但是web服务器并不能直接运行动态脚本,为了解决这一问题,可以使用外部应用程序对web服务器的功能进行扩展,而web服务器与外部应用程序之间的数据通信就遵循CGI协议,外部应用程序也被称为CGI程序。CGI现在也成为了比较原始的开发动态网站的方式。
二、CGI:
CGI是web服务器和外部应用程序之间的协议(注意是协议),通过该协议,可以处理用户端的动态请求。CGI程序就是指的处理用户端动态请求的可执行程序或者脚本。Web服务器接收到的用户端的请求后给CGI程序提供输入,CGI程序对输入进行处理并将结果返回给web服务器,最终web服务器将处理结果转发给客户端,即完成了一次请求的响应。简要工作流程如下图:
1)浏览器通过网页HTML表单或其他方式向服务器发送一个请求;
2)web服务器根据请求的URL创建一个新进程并调用对应的CGI程序,同时为CGI程序准备好输入(环境变量或者是标准输入STDIN);
3)CGI程序获取输入,对输入进行解码后,进行一系列自定义处理,其中可能涉及到对文件系统的读写和对数据库的增删改查等;
4)CGI以标准输出STDOUT的形式将处理结果返回给web服务器,一般是HTML格式的;
5)web服务器摧毁这个进程,并将输出返回给客户端浏览器。
在这个过程中,我们不关注HTTP通信的过程,我们只关注CGI这一部分。首先是输入和输出的问题;第二是分析一下这个过程中存在的缺陷。
输入&输出
输入有两种方式,环境变量和STDIN;输出只有一种STDOUT.
1. 环境变量
以下是一些在CGI程序中比较常用到的环境变量。
其中,可以根据REQUEST_METHOD的取值分为两种情况。
如果REQUEST_METHOD==GET,那么输入就来自于环境变量,储存在QUERY_STRING字段中,CGI程序只需要读取该环境变量就可以获取输入。采用GET方法提交HTML表单数据时,客户端会把这些数据附加到由ACTION标记命名的URL的末尾,例如http://localhost/hello.cgi?name=xxx&id=123,那么QUERY_STRING=name=xxx&id=123。编码规则如下:
CGI程序名和输入之间用“?”分隔; 变量之间用“&”分开; 变量与其对应值用“=”连接; 空格用“+”代替; 保留的控制字符则用“%”连接对应的16进制ASCII码代替; 某些具有特殊意义的字符也用“%”接对应的16进制ASCII码代替; 空格是非法字符; 任意不可打印的ASCII控制字符均为非法字符。
因此,此时CGI程序从环境变量中获得的输入还不是原始的用户数据,还需要按照上述规则进行相应的解码,得到每个变量的值,之后再进行后续处理即可。
使用GET方式,一方面会将输入在URL中进行显示,有违URL的出发点(URL应当只作为网络资源的唯一定位标识);另一方面在环境变量中的输入有长度限制,不能发送大量的数据,这时需要通过POST方式来发送。
2. 标准输入
如果REQUEST_METHOD==POST,那么输入就来自于标准输入,同时传输的用户数据的长度保存在环境变量CONTENT_LENGTH中。CGI程序首先读取环境变量CONTENT_LENGTH的值,获得输入长度len,再从标准输入中读取len长度的数据即可。
采用POST方法,传输的数据不会在URL中显示,并且也没有长度限制,但是需要通过Form发送。
3. 标准输出
CGI在返回响应时只需要向标准输出中写入数据即可,比如使用printf、cout、print、echo等。响应一般为HTML格式,但是需要注意的是,并不是直接输出一段HTML代码就行,而是需要返回一个完整的HTTP响应,报头的部分也需要输出。如:print "Content-Type:text/html\n\n";
缺陷
通过分析CGI的流程,发现每次一个CGI请求,web服务器都需要创建一个新的进程运行CGI程序,并且在启动CGI程序时可能还需要读取一些配置文件、加载一些扩展等操作;在执行完毕后该进程即被销毁,当下次请求到来时,还需要重复上述操作,这严重影响了服务器端的响应效率。
此外,CGI也缺乏URL路由的功能,每个CGI程序都独立提供给外界访问,访问CGI程序的URL中包含了CGI程序的路径信息,就会向外界暴露一些信息,产生不安全的因素。
三、FastCGI(FCGI):
FCGI是对CGI改进的版本,增加了一些扩展功能。FCGI的目标就是要减少web服务器与CGI程序之间创建进程和销毁进程的开销,提高web服务器的效率。FCGI在web服务器启动时加载,并启动多个CGI解释器保存在内存中。FCGI的本质就是一个常驻内存的进程池技术,当有请求到达时不需要耗费时间创建新的进程,只需要由FCGI去调度,选择一个合适的CGI解释器(FCGI子进程)处理请求即可,在一个请求处理完成之后,该处理进程不销毁,继续等待下一个请求的到来。架构图如下:
其工作流程可以分为两个阶段,即准备阶段和循环阶段:
【准备阶段】
1)web服务器启动时,初始化FCGI的程序执行环境,载入FCGI进程管理,如IIS的ISAPI、Apache的Module...;
2)FCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自web服务器的连接;
【循环阶段】
3)浏览器向web服务器发送HTTP请求;
4)web服务器将请求采用socket方式转发到FCGI主进程,FCGI主进程选择并连接到一个CGI解释器,该解释器将执行请求对应的CGI程序,这就是一个FCGI子进程,然后web服务器将标准输入和环境变量发送到FCGI子进程;
5)FCGI子进程处理完成后,将标准输出或错误信息从同一个socket连接返回给web服务器,然后关闭FCGI子进程与web服务器之间的连接,此时不会关闭子进程,而是继续等待下一个连接;
6)web服务器接收到输出后,返回响应。
优点
FCGI具有明显的优势,一是不再需要每次响应动态请求都创建、销毁进程,提高了web服务器的性能,使它可以同时处理大量的请求;二是web服务器不再直接控制CGI程序,FastCGI进程管理器可以独立运行在非web服务器上,实现动静分离,处理压力分散在不同的服务器上。
四、Web服务器与CGI的交互模式:
Web服务器和CGI进程之间的关系就是:web服务器在接收到动态请求后,传递一些参数和环境变量,CGI经过处理后,将处理结果返回给web服务器。这是一个一来一回的过程,下面以Apache httpd和php为例,来说明web服务器和CGI之间的3种交互模式。
(1)CGI模式
在这个模式下,当httpd接收到动态请求后,fork一个CGI进程(php-cgi,即php解释器),并且在启动php-cgi时总是需要加载php.ini等配置文件,然后在这个进程中执行相应的php脚本,CGI进程再将结果返回给httpd,最后该进程被销毁。当有多个动态请求到达时,将先后启动多个进程,因此,这种模式效率很低。
PHP-CGI就是php语言对CGI协议的实现,httpd和php-cgi之间采用CGI模式进行交互。Phpstudy就是这种模式。
(2)内置模块模式
内置模块模式效率要比CGI模式高一些。该模式的做法是将php-cgi的模块(例如php5_module)编译进httpd。在httpd启动时会加载并激活模块,php-cgi也就启动了。php-cgi启动后会常驻在httpd进程内部。当动态请求到达时,httpd不用再生成cgi解释器,而是直接将动态请求转发给它内部的php-cgi。
同时需要注意的是,只有在httpd启动时才会加载php-cgi模块,也就意味着,只有这时候才会加载php的配置文件,所以当php.ini等配置文件被修改后,需要重新启动httpd,修改后的配置文件才会被加载。
(3)PHP-FPM模式
PHP-FPM实现了FastCGI协议。
在该模式中,PHP-FPM充当着进程管理器的角色,在PHP-FPM启动后会创建多个子进程,每个子进程都运行着php-cgi,而且都受到主进程的管理和调控。主进程启动后会对外提供一个socket,当服务器接收到HTTP请求后会将请求按照FastCGI协议封装好交给socket。php-fpm创建的子进程会去争夺socket连接,成功连接到的子进程将处理请求并返回结果。Php-fpm还会监控各个子进程的运行情况,如果发现有子进程异常退出,会重新创建子进程。
五、JS和CGI:
JS只能在客户端浏览器上运行,CGI则是运行在服务器端。虽然JS目前功能很强大、用处很广泛,可以做一些CGI的工作,如表单数据验证等。但是JavaScript也不会取代CGI。如果一项功能既能使用JS完成,也能使用CGI完成,那么就绝对要选JS,执行速度快并且减少了数据传输的消耗也减小了服务器的负担。但如果是一些比如需要和数据库进行交互的功能,那就必须使用CGI完成。
六、ASP:
ASP是Active Server Page的缩写,意为“活动服务器网页”。ASP是微软公司开发的代替CGI脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单、方便的编程工具。ASP的网页文件的格式是.asp,常用于各种动态网站中。ASP是一种服务器端脚本编写环境,可以用来创建和运行动态网页或web应用程序。ASP网页可以包含HTML标记、普通文本、脚本命令以及COM组件等。利用ASP可以向网页中添加交互式内容(如在线表单),也可以创建使用HTML网页作为用户界面的web应用程序。【摘自百度百科】
七、CGI编程:
① 含C、Perl、Python
https://blog.csdn.net/weixin_39609623/article/details/86312439
② Python--菜鸟教程
https://www.runoob.com/python/python-cgi.html
参考链接:
[1] CGI百科
[2] CGI是什么
[3] 万物归宗--CGI
[6] 简单说明CGI和动态请求是什么