简介
WSGI(web server gataway interface),是一个规范,在python规范中由PEP333说明,用于描述web server和web application的通信,要实现WSGI需要同时实现符合WSGI的web服务器和web应用。其主要目的是为了通过统一的标准解耦服务器和应用,使得应用可以自由和服务器进行搭配,从而避免在选定某种web框架的情况下只能使用特定的服务器的问题。
问题
1、很多的博客都对wsgi进行了说明和理解,但是这些理解中没有过多的区分一些概念以及wsgi实现的情况;
2、我也查看了PEP333的说明,无论是英语原文还是找到的几版翻译,PEP333的描述都比较晦涩;
3、网上各种名词很多,会产生一些疑问:
- flask、django等被称为web框架,大部分说明中把他们放在应用层,然而flask依赖于werkzurg,werkzurg有一个server,django本身就是一套完整的服务器+应用的实现,因此往往让我们思考flask、django在wsgi中到底是什么?
- 很多博客中使用图或者文字描述wsgi的分层结构,有的里面将wsgi作为一个中间层,但是PEP333中有说明wsgi描述了服务器和应用的api规范,应该是同时包含了服务器端和应用端。所以又有了wsgi server和wsgi app的说法。
- 在PEP333中有对于中间件的描述,实际中的中间件是什么样的?
- python的web应用线上用到nginx,apache等,它们是否wsgi server?gunicorn本身是wsgi服务器,在nginx+gunicorn这种组合中,nginx和gunicorn是什么关系?
WSGI理解
这里我将说一下我对wsgi的理解。首先说明一下WSGI的http通信的过程,下面是从网上找到的一张图,图中说明了基于WSGI的请求和响应的过程。这张图中将WSGI的实现表示为WSGI Server和WSGI App,我的理解是,WSGI广义的来说是指实现了WSGI接口描述的Server和App,狭义的来说是指Server和App实现的那个部分,所以对于如Apache实现了支持wsgi的扩展mod_wsgi,这种情况下面即只是指这个扩展而已,而应用比较简单,基本框架都是直接按照wsgi app接口去做的实现,不存在支持多种规范的情况。
图中说明了从浏览器的请求如何被基于WSGI实现的服务器和应用处理的,其主要步骤如下:
- 浏览器发起http请求;
- server处理请求,将其封装成相应的信息,这里在PEP333中规定有一个environ的环境参数;
- server调用app,app是一个对象,在python中app可以是函数,类对象,类,类对象一般都是通过app实现的__call__实现,类一般在__init__实现时带上wsgi约定的参数。比如Flask、bottle的web application是实现了__call__的类。
- app进行逻辑处理,比如从数据库获取数据等;
- 返回HTTP状态码和报文头。因为在PEP333的app接口描述中是传入了一个start_response的函数,这个函数在app中调用进行返回所以是直接对浏览器进行返回了;
- 返回正文给服务器,一般是返回一个可迭代的对象给server进行处理;
- 服务器返回HTTP正文给浏览器。
通过以上的说明可以知道,Django、Flask等自带的Server,可以认为是WSGI的实现,但是实际生产中这些web框架实现的server能力比较弱,所以其优势在app上,因此被作为app端的框架使用。另外wsgi服务器在python中有一个内置的WSGIREF,可以用于开发环境,实际生产中可以使用gunicorn、uWSGI等,详见:http://wsgi.readthedocs.io/en/latest/servers.html。
值得说明的是,gunicorn本身实现其实主要用于动态请求,这样实现比较容易,也不用去模仿好的服务器造轮子,对于没有静态文件请求,只有api访问,业务量不大的时候可以使用,但是业务量比较大的时候可能需要负载均衡,因此实际使用中往往是通过nginx+gunicorn来使用的。uWSGI使用了一个uwsgi的协议,是该服务器的独占协议。这里容易误导理解。另外在网上有把服务器分为web服务器和应用服务器的说法,web服务器可以是nginx、Apache等,而gunicorn,uWSGI等成为应用服务器,是wsgi应用的容器。只是在实际中gunicorn,uWSGI以及那些框架自己测试用的wsgi服务器也都支持http协议,因此也可以直接用来使用,只是性能不够好。这种说法利于去区分一下服务器之间的区别和联系,但是在PEP333中,对wsgi server也直接称为了web server。
中间件
通过以上的解释可以知道wsgi连接了server和app,那么如果我们为了实现某个通用的功能从而同时实现server和app的接口,这样就可以插入server和app中间,让server以为自己连接的是app,而app认为自己连接的是server。
如图这里表现了app和server的关系,他们通过wsgi连接起来,而中间件则同时能够和app于server连接,而中间件之间也可以相互连接。这种方式可以让每个模块都专注于自己的开发,比如路由处理,session处理等,而app框架只需要关注其需要实现的东西,从而能够利用最好的工具实现整套服务。