网关协议:CGI和WSGI
通常服务器程序分为web服务器和应用程序服务器。web服务器是用于处理HTML文件,让客户可以通过浏览器进行访问,主流的web服务器有Apache、IIS、Nginx、lighthttpd等。应用服务器处理业务逻辑,比如使用Python的Django、flask写的程序。通常来自客户端浏览器的请求被web服务器截获,如果是静态请求,则如Nginx会自己做处理,如果是动态请求,则会抛给后端应用服务器来处理。于是如何在web服务器与应用服务器之间进行通信成了主要问题,这就引出了以下三种处理的接口:CGI、FastCGI、WSGI。
CGI
通用网关接口(Comman Gateway Interface)描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的应用程序请求数据。CGI独立于任何语言,CGI程序可以是任何脚本语言或完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell、Python、Ruby、PHP、Perl、C/C++和VB都可以用来编写CGI程序。最初CGI是在1993年由美国国家超级电脑应用中心为NCSA HTTPd web服务器开发的。这个web服务器使用了Unix shell环境变量来保存从web服务器传递出去的参数,然后生成一个运行CGI的独立的进程。CGI的处理流程如下图所示:

- web服务器收到客户端(浏览器)的请求http request,启动CGI程序,并通过环境变量、标准输入传递数据;
- CGI进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等;
- CGI进程将处理结果通过标准输出、标准错误,传递给web服务器;
- web服务器收到CGI返回的结果,构建http response返回给客户端,并杀死CGI进程,web服务器与CGI通过环境变量、标准输入、标准输出、标准错误传递数据;
CGI使外部程序与web服务器之间交互成为可能。CGI程序运行在独立的进程中,并对每个web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降,此外,由于地址空间无法共享,业限制了资源重用。
FastCGI
快速通用网关接口(Fast Comman Gateway Interface)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少web服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的web请求。与为买个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。

当进来一个请求时,web服务器把环境变量和这个页面请求通过Unix domain socket(都位于同一物理服务器)或者一个IP socket(FastCGI部署在其他物理服务器)传递给FastCGI进程。

- web服务器启动时载入初始化FastCGI执行环境,例如IIS ISAPI,Apache mod_fastcgi、nginx_ngx_http_fastcgi_module、lighthttpd mode_fastcgi;
- FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自web服务器的连接。启动FastCGI进程时,可以配置ip socket或Unix domain socket两种启动方式;
- 当客户端请求到达web服务器时,web服务器将请求采用socket方式发到FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。web服务器将CGI环境变量和标准输入发送到FastCGI子进程;
- FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回web服务器。当FastCGI子进程关闭连接时,请求便处理完成;
- FastCGI子进程接着等待并处理来自web服务器的下一个连接;
由于FastCGI程序不需要不断地产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率至少要比CGI技术提高5倍以上。它还支持分布式部署,即FastCGI程序可以在web服务器以外的主机上运行。
CGI就是所谓的短生存期应用程序,FastCGI就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork(这是CGI最为人诟病的fork-and-execute模式)。
WSGI
web服务器网关接口(Python Web Server Gateway Interface)是为Python语言定制的web服务器和web应用程序或框架之间的一种简单通用的接口。自从WSGI被开发出来之后,许多其他语言中也出现了类似接口。WSGI是作为web服务器与web应用程序或应用框架之间的一种低级别的接口,以提升可移植web应用开发的共同点。WSGI是基于现存的CGI标准而设计的。
WSGI分为两个部分:一为"服务器"或"网关",另一为"应用程序"或"应用框架"。在处理一个WSGI请求时,服务器会为应用程序提供环境资讯及一个回调函数(callback function)。当应用程序完成处理请求后,透过前述的回调函数,将结果回传给服务器。所谓的WSGI中间件同时实现了API的两方,因此可以在WSGI服务和WSGI应用之间起调解作用:从WSGI服务器的角度来说,中间件扮演应用程序,而从应用程序角度来说,中间件扮演服务器。"中间件"组件可以执行以下功能:
- 重写环境变量,根据目标URL,将请求消息路由到不同的应用对象;
- 允许在一个进程中同时运行多个应用程序或应用框架;
- 负载均衡和远程处理,通过在网络上转发请求和响应消息;
- 进行内容后处理,例如应用XSLT样式表;
以前,如何选择合适的web应用程序框架成为困扰Python初学者的一个问题,这是因为,一般而言,web应用框架的选择将限制可用的web服务器的选择,反之亦然。那时的Python应用程序通常为CGI、FastCGI、mod_python中的一个设计,甚至是为特定web服务器的自定义的API接口而设计的。WSGI没有官方的实现,因为WSGI更像一个协议。只要遵循这些协议,WSGI应用(application)都可以在任何服务器(server)上运行,反之亦然。WSGI就是Python的CGI包装,相对于FastCGI是PHP的CGI包装。
WSGI将web组件分为三类:web服务器、web中间件、web应用程序,WSGI基本处理模式为:

1、wsgi server/gateway
wsgi server可以理解为一个符合WSGI规范的web server,接收request请求,封装一系列环境变量,按照wsgi规范调用注册的wsgi app,最后将response返回给客户端。文字很难理解清楚wsgi server到底是什么东西,以及做些什么事情,最直观的方式还是看wsgi server的实现代码。以Python自带的wsgiref为例,wsgiref是按照wsgi规范实现的一个简单wsgi server。

- 服务器创建socket,监听端口,等待客户端连接;
- 当有请求来时,服务器解析客户端信息放到环境变量environ中,并调用绑定的handler来处理请求;
- handler解析这个http请求,将请求信息如method、path等放到environ中;
- wsgi handler再将一些服务器信息也放到environ中,最后服务器信息,客户端信息,本次请求信息全部都保存到了环境变量environ中;
- wsgi handler调用注册的wsgi app,并将environ和回调函数传给wsgi app;
- wsgi app将response header/status/body回传给wsgi handler;
- 最终handler还是通过socket将response信息返回给客户端;
2、wsgi application
wsgi application就是一个普通的callback对象,当有请求到来时,wsgi server会调用这个wsgi app。这个对象接收两个参数,通常为environ,start_response。environ就是前面介绍的,可以理解为环境变量,跟一次请求相关的所有信息都保存在了这个环境变量中,包括服务器信息,客户端信息,请求信息。start_response是一个callback函数,wsgi application通过start_response,将response header/status返回给wsgi server。此外这个wsgi app会返回一个迭代器对象,这个迭代器对象就是response body。
3、wsgi middleware
有些功能可能介于服务器程序和应用程序之间,例如,服务器拿到了客户端请求的URL,不同的URL需要交由不同的函数处理,这个功能叫URL路由,这个功能就可以放在二者中间实现,这个中间层就是middleware。middleware对服务器程序和应用都是透明的,也就是说,服务器程序以为它就是应用程序,而应用程序以为它就是服务器。这就告诉我们,middleware需要把自己伪装成一个服务器,接收应用程序,调用它,同时middleware还需要把自己伪装成一个应用程序,传给服务器程序。其实无论是服务器程序,middleware还是应用程序,都在服务端,为客户提供服务,之所以把它们抽象成不同层,就是为了控制复杂度,使得每一次都不太复杂,各司其职。
uwsgi
uwsgi旨在为部署分布式集群的网络应用开发一套完整的解决方案。uwsgi主要面向web及其标准服务,已经成功的应用于多种不同的语言。由于uwsgi的可扩展架构,它能够被无限制的扩展用来支持更多的平台和语言。目前可以使用C,C++和Object-C来编写插件。项目名称中的wsgi是为了向同名的Python web标准表示感谢,因为wsgi为该项目开发了第一个插件。uwsgi是一个web服务器,它实现了wsgi协议、uwsgi协议、http等协议。uwsgi既不用wsgi协议也不用FastCGI协议,而是自创了一个uwsgi协议,uwsgi协议是一个uWSGI服务器自由的协议,它用于定义传输信息的类型,每一个uwsgi packet前4字节为传输信息类型描述,它与WSGI相比是两样东西,据说该协议大约是fcgi协议的10倍快。uWSGI主要特点如下:
- 超快的性能;
- 低内存占用(实测为Apache2的mod_wsgi的一半左右);
- 多app管理;
- 详尽的日志功能(可以用来分析app性能和瓶颈);
- 高度可定制(内存大小限制,服务一定次数后重启等);
网关协议:CGI和WSGI的更多相关文章
- openstack项目【day23】:keystone组件网关协议
本节内容 一 静态页面和动态页面 二 什么是web server 三 什么是网关协议 3.1 引子 3.2 网关协议 四 网关协议CGI.FastCGI.WSGI.UWSGI 五 网关协议与keyst ...
- keystone系列三:网关协议
一 静态页面和动态页面 在了解了http协议后,我们知晓,一个web server的本质就是 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP响应 ...
- openstack 之~keystone之网关协议
第一:静态页面和动态页面 上一篇博客介绍了HTTP后,我们知道一个web server的本质就是 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP ...
- 网关协议学习:CGI、FastCGI、WSGI、uWSGI
一直对这四者的概念和区别很模糊,现在就特意梳理一下它们的关系与区别. CGI CGI即通用网关接口(Common Gateway Interface),是外部应用程序(CGI程序)与Web服务器之间的 ...
- 网关协议学习:CGI、FastCGI、WSGI
网关协议学习:CGI.FastCGI.WSGI https://www.biaodianfu.com/cgi-fastcgi-wsgi.html
- 网关协议:CGI、FastCGI、WSGI
CGI就像是一座桥,把网页和WEB服务器中的执行程序连接起来,它把HTML接收的指令传递给服务器的执行程序,再把服务器执行程序的结果返还给HTML页. CGI CGI即通用网关接口(Common Ga ...
- 【转】网关协议学习:CGI、FastCGI、WSGI、uWSGI
一直对这四者的概念和区别很模糊,现在就特意梳理一下它们的关系与区别. CGI CGI即通用网关接口(Common Gateway Interface),是外部应用程序(CGI程序)与Web服务器之间的 ...
- OpenStack☞网关协议
一 动态页面与静态页面区别 静态页面:每一个网页都有一个固定的URL,且网页的URL以.html..htm..shtml等常见的形式为后缀. 网页内容已经发布到网站服务器上,无论是否有用户访问,每个静 ...
- 漫谈CGI FastCGI WSGI
作者:auxten链接:https://zhuanlan.zhihu.com/p/20054757来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. CGI(Common ...
随机推荐
- shell 判断字符串是否包含另一个字符串
1.使用grep s1="abcdefg" s2="bcd" result=$(echo $s1 | grep "${s2}") if [[ ...
- tp框架基础控制器调用方法
public function indd(){ //调用该控制器下的某个方法 $this ->index(); //跨控制器调用 $k = A("index");// 创建控 ...
- PHP chroot() 函数
改变根目录: <?php// Change root directorychroot("/path/to/chroot/"); // Get current director ...
- POJ 2387 Til the Cows Come Home (dijkstra模板题)
Description Bessie is out in the field and wants to get back to the barn to get as much sleep as pos ...
- 为什么不能在shell脚本中执行source /etc/profile或者source ~/.bashrc问题?
执行脚本时,其中的命令是在一个子shell中执行的.子shell继承了父shell的环境变量,但无法修改他们,或者说所做的修改仅对子shell有效.
- delphi中SendMessage使用说明
SendMessage基础知识 函数功能:该函数将指定的消息发送到一个或多个窗口.此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回.而函数PostMessage不同,将一个消息寄送到一个线 ...
- 微信公众号ios10.1 版本白屏问题
真机调试IOS 10.1.x的版本不支持fetch 所以一直loading显示白屏. 其他设备都没问题. 所以用主要属性window.fetch用来判断是否支持fetch 属性 import { ba ...
- 判断数组中值为empty
const n = this.item.answerSelfId.length; let num = 0; for (let m = 0 ; m < n ; m++) { if ( !this. ...
- Intellij IDEA 安装Scala插件 + 创建Scala项目
一.IDEA 2018 Ultimate edition (旗舰破解版下载地址) 百度网盘地址:https://pan.baidu.com/s/1d9ArRH6adhDUGiJvRqnZMw 二.I ...
- redis zset 介绍
$key = 'key'; //新增 zadd($key,分数,标识) //删除某个标识 zrem($key,标识) //查询某个标识的排名(从0开始的 所有在输出的时候要加一) zrevrank($ ...