ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 6.1 CGI HTTP协议早期设计是一个通信应答协议,服务器不记录任何状态。 简单来说如下: 客户端请求服务器上的abc.html,服务器给客户端返回abc.html,完事儿结束。 想象一下客户端如果持续请求abc.html 100次,那么服务器傻傻的提供100次,因为服务器根本不记录任何状态,所以你要了,我就给就是。 这样设计的好处是足够简单,但是显然不是那么合理。 但是WWW发展,需要HTTP协议有更加强大的功能,更多需要和服务器的交互。 打个比方,登录淘宝时,每个用户进入相同的页面,但是输入了不同的用户名和密码,然后提交到服务器。 提交到服务器之后,服务器需要对用户名和密码进行验证。这种提交,显然请求的不能是简单的请求一个文件资源,而应该是调用服务器的某个方法,某个函数。 这个功能可以通过CGI来实现。 CGI是一个可执行程序,它能响应用户的请求,这个可执行程序可以使用任何语言来编写。 ## 6.1 .CGI 通用网关接口(Common Gateway Interface/CGI)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script, Python, Ruby, PHP, perl, Tcl, C/C++, 和 Visual Basic 都可以用来编写 CGI 程序。 最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量 来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。cgi的处理流程如下图所示: ![](https://img.kancloud.cn/68/cc/68cc694a56186704a2057910834c4dd2_1038x826.png) * step1. web 服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据 * step2. cgi进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等 * step3. cgi程将处理结果通过标准输出、标准错误,传递给web 服务器 * step4. web 服务器收到cgi返回的结果,构建Http Response返回给客户端,并杀死cgi进程 web服务器与cgi通过环境变量、标准输入、标准输出、标准错误互相传递数据。 >在遇到用户连接请求: >1 先要创建cgi子进程,然后cgi子进程处理请求。处理完事退出这个子进程:fork-and-execute >2 cgi方式是客户端有多少个请求,就开辟多少个子进程,每个子进程都需要启动自己的解释器,加载配置,连接其他服务器等初始化工作,这是cgi进程性能低下的主要原因。当用户请求非常多的时候,会大量的占用内存、cpu等资源。造成性能低下。 ### 环境变量 GET请求,它将数据打包放置在环境变量QUERY_STRING中,CGI从环境变量QUERY_STRING中获取数据。常见的环境变量如下表所示: | 环境变数 | 内容 | | -- | -- | | AUTH_TYPE |存取认证类型。| | CONTENT_LENGTH | 由标准输入传递给CGI程序的数据长度,以bytes或字元数来计算。 | | CONTENT_TYPE | 请求的MIME类型| | GATEWAY_INTERFACE | 服务器的CGI版本编号。 | | HTTP_ACCEPT |浏览器能直接接收的Content-types, 可以有HTTP Accept header定义. | | HTTP_USER_AGENT |递交表单的浏览器的名称、版本 和其他平台性的附加信息。 | | HTTP_REFERER| 递交表单的文本的 URL,不是所有的浏览器都发出这个信息,不要依赖它 | | PATH_INFO | 传递给cgi程式的路径信息| | QUERY_STRING |传递给CGI程式的请求参数,也就是用"?"隔开,添加在URL后面的字串。| | REMOTE_ADDR | client端的host名称 | | REMOTE_HOST | client端的IP位址。 | | REMOTE_USER |client端送出来的使用者名称。 | | REMOTE_METHOD | client端发出请求的方法(如get、post)。 | | SCRIPT_NAME | CGI程式所在的虚拟路径,如/cgi-bin/echo。 | | SERVER_NAME | server的host名称或IP地址。 | | SERVER_PORT| 收到request的server端口。 | | SERVER_PROTOCOL |所使用的通讯协定和版本编号。 | | SERVER_SOFTWARE | server程序的名称和版本。| ## 标准输入 环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行CGI程序。因此后来又发展出另外一种方法:POST,也就是利用I/O重新导向的技巧,让CGI程序可以由STDIN和STDOUT直接跟浏览器沟通。 当我们指定用这种方法传递请求的数据时,web 服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变数,然后调用CGI程式并将CGI程序的STDIN指向这块缓冲区,于是我们就可以很顺利的通过STDIN和环境变数CONTENT_LENGTH得到所有的资料,再没有资料大小的限制了。 总结:CGI使外部程序与Web服务器之间交互成为可能。CGI程式运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限制了资源重用。