什么是通用网关接口CGI( Common Gateway Interface)?

通用网关接口CGI

1、背景

早期的Web服务器,只能响应浏览器发来的HTTP静态资源的请求,并将存储在服务器中的静态资源返回给浏览器。随着Web技术的发展,逐渐出现了动态技术,但是Web服务器并不能够直接运行动态脚本,为了解决Web服务器与外部应用程序(CGI程序)之间数据互通,于是出现了CGI(Common Gateway Interface)通用网关接口。简单理解,可以认为CGI是Web服务器和运行其上的应用程序进行“交流”的一种约定。

在这里插入图片描述

2、预备前端知识

一次网页请求与响应

在进行网页浏览时,通常就是通过一个URL请求一个网页,然后服务器返回这个网页文件给浏览器。浏览器在本地解析该文件渲染成我们看到的网页。然而通常我们看到的网页不是静态网页,也就是说在服务端是没有这个网页文件,它是在网页请求的时候动态生成的,比如PHP/JSP网页。依据你请求的参数不同,所返回的内容不同。

同理,如果是请求一个CGI程序的时候(比如在浏览器直接输入CGI程序的URL,或者提交表单的时候发送给CGI程序),CGI程序负责解析从前端传递过来的参数,理解它的意图然后返回数据,比如返回HTML、XML或JSON等。】

预备前端知识

假设你是一个C++程序员,你可能对前端不熟(OK,我也不熟),在接下来的讲述之前,你要先掌握一些预备的前端知识(尽量少讲前端),你不需要知道如何渲染出一个美轮美奂的网页,但你需要知道前、后端如何交互。前端页面如何发送数据,一个普通的HTML页面通常的做法,你只需知道如下几种:

  • form表单提交(html原生)
  • js操纵下的表单提交
  • js通过Ajax请求数据
<h1>表单提交</h1>
<form action="/cgi-bin/hello.cgi" method="get">
<table>
	<tr>
		<td>用户名:</td>
		<td><input name="username"/></td>
	</tr>
		<tr>
		<td>密码:</td>
		<td><input name="password"/></td>
	</tr>
	<tr>
		<td><input type="submit" value="OK"/></td>
	</tr>
	</table>
</form>

form标签的action属性的值表示的就是表单要提交到url,即表单提交以后要跳转的页面(Ajax可以达到无跳转拉取数据,刷新页面),这里action属性值的是cgi程序的url地址。(WARNNING:/ 对应的是网站根目录,而不是Linux文件系统根目录哦)。method属性表示数据请求方式,有两种:get和post。不赘述。

在这里插入图片描述
我输入用户名jellywang,密码123456之后,点击OK按钮,即向 当前域名/cgi-bin/hello.cgi 的程序序提交了表单,并且携带参数username=jellywang。然后页面会跳转到这个cgi(就像普通网页跳转,浏览器地址栏更新一样)。

如果是get请求。那么浏览器地址栏的URL看起来像这样:localhost:/cgi-bin/hello.cgi?username=jelly&password=123456。很显然这是一种不够安全的方式,所以我们还可以使用post请求。这样地址栏就看不到这种提交的参数了。(其实post也不够安全,不鼓励直接提交明文密码的方式,本文仅作示例,安全登录不上本文重点)

第一个CGI

#include 〈工ostream >
using namespace std;

int main ()
{
	cout << ” Content-type : text/html\r \n \r \n ”;
	cout <<<html>\n”;
	cout <<<head>\n ”;
	cout <<<title>Hello World - First CGI Program</title>\n ”;
	cout <<</head>\n”;
	cout <<<body>\n”;
	cout <<<h2>Hello World! This is my first CGI program</h2>\n ”;
	cout  << ”</ body >\n ”;
	cout  <<</html>\n ” ,
return 0;

编译,手动执行一次,由于本程序只是单纯输出一些信息,所以可以直接执行;之后再将其复制到Apache 的cgi-bin 目录下。
在这里插入图片描述
在浏览器中输入“ http:/142.96.142.129:8083 /cg i-bin/test ”, 提示“ He llo World! This is my first CGI program ”,则表示运行成功了,

在这里插入图片描述

3、什么是CGI

  • CGI( Common Gateway Interface,通用网关接口)是HTTp协议中最重要的技术之有着不可替代的重要地位。
  • CGI是一个web服务器提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。
  • 组成CGI通信系统的是两部分:一部分是HTML页面,就是在用户端浏览器上显示的页面;另一部分则是运行在服务器上的CGI程序。它们之间的通信方式。
  • CGI是一个标准化的协议,能够使应用程序(通常称为CGI程序或CGI脚本)同web服务器和客户端进行交互。CGH程序能够用Python、PERL、 Shell, C或C++等语言来实现。

在这里插入图片描述
在这里插入图片描述
简单点的具体操作流程:

CGI是Web服务器和一个独立的进程之间的协议,它会把HTTP请求Request的Header头设置成进程的环境变量,HTTP请求的Body正文设置成进程的标准输入进程的标准输出设置为HTTP响应Response,包含Header头和Body正文。
在这里插入图片描述

4、CGI使用原理

基本概念

对于一个CGI程序,主要的工作是从环境变量和标准输入中读取数据,然后处理数据,最后向标准输出中输出数据

  • 1、环境变量

环境变量中存储的叫做Request Meta-Variables,也就是诸如QUERY_STRING、PATH_INFO之类的,这些都是由Web服务器通过环境变量传递给CGI程序的,CGI程序也是从环境变量中读取的。

对于CGI程序来说,它继承了系统的环境变量。CGI环境变量在CGI程序启动时初始化,在结束时销毁。当一个CGI程序不是被HTTP服务器调用时,它的环境变量几乎是系统环境变量的复制。当这个CGI程序被HTTP服务器调用时,它的环境变量就会多了以下关于HTP服务器、客户端、CGI传输过程等项目。

CGI相关的环境变量有3种:与请求相关的环境变量、与服务器相关的环境变量和与客户端相关的环境变量,详细见表。
在这里插入图片描述
这些环境变量是从何而来,是谁定义的?是Linux吗?POSIX吗?

当然不是。这里就要再次声明一下CGI是一个接口协议,这些环境变量就是属于该协议的内容,所以不论你的server所在的操作系统是Linux还是Windows,也不论你的server是Apache还是Nginx,这些变量的名称和含义都是一样的。实际就是Apache/Nginx在将这些内容填充到环境变量中,而具体填充规范则来自于CGI接口协议。

在C语言标准中有获取环境变量值得库函数——getenv。(头文件stdlib.h)

//比如
chr* str = NULL;
str = getenv("QUERY_STRING");

对于get请求,可以从环境变量QUERY_STRING中取出字符串 username=jelly&password=123456。然后程序自己做字符串的解析操作,解析出参数的key和value。而对于post请求,则是直接通过标注输入(STDIN)来获取这个参数字符串,比如使用scanf或cin都可以。

  • 2、标准输入,输出

Web服务器在接收到用户浏览器的HTTP请求,比如请求如下URL:

http://guodongxiaren.me/cgi-bin/helloworld.cgi

此时在Web服务器调用helloworld.cgi之前,会把各类HTTP请求中的信息以环境变量的方式写入OS。CGI程序本质是OS上一个普通的可执行程序,它通过语言本身库函数来获取环境变量,从而获得数据输入。

除环境变量外,另外一个CGI程序获取数据的方式就是标准输入(stdin)。如post请求一个CGI的URL,那么POST的数据,CGI是通过标准输入来获取到的。

而CGI如何构造出数据(比如HTML页面)返回给浏览器呢?其实CGI本身只要向标准输出去写入数据即可。比如printf、cout,比如System.out.println,又比如print、echo等。因为Web服务器已经做了重定向,将标准输出重定向给Web服务器的与浏览器连接的socket。

此时要注意的是,不要以为返回HTML页面,那么直接输出一段HTML代码就OK,注意。此时CGI的输出承担的是HTTP协议的响应部分,因此HTTP响应报头也要自己标准输出出来。比如:

cout<<"Content-Type:text/html\n\n"<<endl;  

这里要注意

一定要输出两个换行符(\n)。因为HTTP协议的首部和消息实体(如HTML代码)之间用空行分割。 后面直接cout出html代码(比如输出你刚才输入的用户名成功登陆)。前端页面就会收到这些html代码,然后浏览器就渲染成网页啦。这就是一次CGI完成的动态网页操作了。

CGI程序的工作原理
在这里插入图片描述
Web服务器一般只用来处理静态文件请求,一旦碰到动态脚本请求,Web服务器主进程就会Fork创建出一个新的进程来启动CGI程序,也就是将动态脚本交给CGI程序来处理。启动CGI程序需要一个过程,如读取配置文件、加载扩展等。当CGI程序启动后会去解析动态脚本,然后将结果返回给Web服务器,最后由Web服务器将结果返回给客户端,之前Fork出来的进程也随之关闭。这样,每次用户请求动态脚本,Web服务器都要重新Fork创建一个新进程去启动CGI程序,由CGI程序来处理动态脚本,处理完成后进程随之关闭,其效率是非常低下的。

在这里插入图片描述

5、缺点

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

时势造英雄,FastCGI(简称FCGI)技术应运而生。简单来说,其本质就是一个常驻内存的进程池技术,由调度器负责将传递过来的CGI请求发送给处理CGI的handler进程来处理。在一个请求处理完成之后,该处理进程不销毁,继续等待下一个请求的到来。

当然FCGI其实也并不是什么惊世骇俗的创意,很容易联想到的解决思路。资源池是后台性能优化中的常见套路。Java发明的Servlet技术也是一种常驻内存的网关通信技术,只不过它采用的是多线程而非进程。

参考

1、https://zhuanlan.zhihu.com/p/25013398
2、https://www.jianshu.com/p/c4dc22699a42

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值