首页 > 代码库 > CGI的知识点

CGI的知识点

CGI(Common Gateway Interface)是能让webserver和CGI脚本共同处理客户的请求的协议。

它的协议定义文档是http://www.ietf.org/rfc/rfc3875。

当中Webserver负责管理连接,传输数据,网络交互等。

至于CGI脚本就负责管理详细的业务逻辑。

Webserver的功能是将client请求(HTTP Request)转换成CGI脚本请求。然后运行脚本,接着将CGI脚本回复转换为client的回复(HTTP Response)。

CGI的脚本请求有两部分:请求元数据(request meta-variables)和相关的消息体(message-body)。

请求元数据

包括:

                               "AUTH_TYPE" | "CONTENT_LENGTH" |
                           "CONTENT_TYPE" | "GATEWAY_INTERFACE" |
                           "PATH_INFO" | "PATH_TRANSLATED" |
                           "QUERY_STRING" | "REMOTE_ADDR" |
                           "REMOTE_HOST" | "REMOTE_IDENT" |
                           "REMOTE_USER" | "REQUEST_METHOD" |
                           "SCRIPT_NAME" | "SERVER_NAME" |
                           "SERVER_PORT" | "SERVER_PROTOCOL" |
                           "SERVER_SOFTWARE" | scheme |
                           protocol-var-name | extension-var-name
 
以下一个一个看:
 
AUTH_TYPE是唯一标识了用户的认证方式,比方basic,Digest等
CONTENT_LENGTH是请求消息体的长度
CONTENT_TYPE是标识消息体的格式
GATEWAY_INTERFACE标识使用的CGI的版本号,比方CGI/1.1
PATH_INFO说明了解释CGI脚本的地址
PATH_TRANSLATED就是能够被訪问的cgi的路径。它相应CGI脚本的路径。比方
http://somehost.com/cgi-bin/somescript/this%2eis%2epath%3binfo
相应的PATH_INFO就是/this.is.the.path;info
QUERY_STRING 请求參数(GET的參数就是放在这个里面的)
REMOTE_ADDR标识client的ip地址
REMOTE_HOST标识的是client的域名
REMOTE_IDENT是发出请求的使用者标示,大多数服务端选择忽略这个属性
REMOTE_USER是使用者的合法名称
REQUEST_METHOD是请求方法,包含GET/POST/PUT/DELETE等
SCRIPT_NAME是脚本程序的虚拟路径。比方是/test/test.php
SERVER_NAME是WEBserver的域名
SERVER_PORT是WEBserverport名
SERVER_PROTOCOL是WEBserver与client的交互请求协议
SERVER_SOFTWARE发送给client的response的Webserver的标识。比方nginx/1.0.6

请求消息体

就是直接将client的请求消息体转发。将消息体放在stdin中传递给script的
 

相关知识点

參数传递

以下的问题就是webserver获取了http请求后。因为http请求是有分GET和POST等方法的。參数怎么传递给可运行程序呢?
比方GET方法,CGI程序就会从环境变量QUERY_STRING中获取数据。
POST呢?Webserver会通过stdin(标准输入)想CGI中传送数据的。而传送的数据长度就是放在CONTENT_LENGTH中的。
相应于HTTP请求。QUERY_STRING存放http的GET參数,stdin存放HTTP的BODY參数
如今流行的nginx+php的方法就是使用nginx(webserver)将请求变成cgi请求到php-cgi上,然后php-cgi进程运行php,将返回值变成cgi response返回给nginx。

nginx再将它变成http回复返回给client。

可是这里有个问题,cgi是单进程的,一个进程的生命期就仅仅是请求进来。处理。返回回复这几个阶段。可是webserver都是须要接受多个web请求的,这里就须要在后端开启多个cgi了。一般的cgiserver都会设置同意开启多少个cgi的数量的。
这里要明白一点,cgi是有分服务端和client的差别的,cgiclient是放在webserver一側,像nginx。apache这种webserver就已经是实现了这个client。

server端须要另外重新启动。像nginx+cgi+php这种配合就须要启动php-cgi服务,当然你也能够想到这种服务一定是以deamon的形式在后台执行,然后会fork出非常多个cgi进程。

 

复用

当然有人会问,cgi进程不能复用是个问题,为什么不呢。fastcgi出现就是攻克了这个问题。它的一个进程能够处理多个请求。这样速度当然就升上去了。然后另一种cgi是scgi(simple cgi),scgi和fastcgi相似,仅仅能说它定义的协议更简单(所以才叫做simple)。scgi的client是c写的,服务端是perl写的。

就最常见的nginx+cgi+php来说。要明白一点php中$_SERVER中获取的信息实际都是从cgi中获取的,当然这个和nginx中获取的client信息是一致的。另外因为cgi是有client和服务端的差别的,因此非常easy想到cgiclient须要使用tcp与client连接,每一个连接当然须要占用一个port,因此还是会有port限制的。所以从这个角度上说。并非cgi开的越多越好(当然6w的port限制是远远够的了)。
 

安全

关于开启的cgi安全问题。以前鸟哥就爆出了一个bug:http://www.laruence.com/2010/05/20/1495.html
有兴趣的读者能够看看。
 
还有cgiserver不是在监听port吗?怎么防止外网的请求运行cgi呢?我们一般的办法就是直接绑定在127.0.0.1的ip地址上。保证仅仅有本机才干訪问

參考文档:

http://www.lyinfo.net.cn/webclass/cgi/default.htm
http://blog.csdn.net/ablo_zhou/article/details/3634954
http://www.ietf.org/rfc/rfc3875

CGI的知识点