WSGI, 全称为 Web Server Gateway Interface。python
它不是什么框架,它是一个规范,可是做为一个规范,它实际上并无官方标准。
这里要说明一下,PEP-0333并非用来规范WSGI用得,而是PEP-0333提出应该有那么一个东西用来处理web服务器和应用服务器之间的关系,所以产生了WSGI。nginx
由于,就目前来看,Web服务通常按照以下方式部署:web
先部署一个web服务器(Apache etc.)用于处理协议层的业务,好比,单台物理机多服务(多域名或者多端口)、负载均衡等。apache
而后部署一个应用服务器(Django etc.),它用于处理具体业务方面的事情,好比,滴滴打车的应用服务器就会处理打车订单CRUD,处理完成以后呢再返回给web服务器,web服务器收到响应以后再返回给客户端。服务器
经过上文,咱们能够了解到WSGI无非作了两件事:app
让Web服务器知道如何调用Python应用程序并把从客户端来的请求拿过来。负载均衡
让Python应用程序知道客户端的具体请求是什么,以及如何返回结果给Web服务器并帮助Python应用程序把计算后的结果返回给Web服务器。框架
也就是说,WSGI是链接Web服务器和应用服务器的桥梁。测试
目前实现的WSGI中,有两个角色,分别是Server/Gateway和application/framework。设计
当请求来临的时候,server
调用application
,而后application
把结果返回给server
。
接下来,server
须要知道去哪可以找到application
。实现这一逻辑,须要在server
指定一个Python模块(具体在server的哪一个位置保存这一路径,那就得根据具体server类型来选择了,如apache或nginx)该模块必须包含一个名称为application
的可调用对象,这个对象的形式以下:
在PEP-0333中指出了,一个WSGI的application角色,应该是一个可调用对象:
def application(environ, start_response)
其中,environ
是一个包含了关于此次HTTP请求信息的字典,start_response
是一个可调用对象,用于在application
中执行,用以在返回响应内容前设置响应的状态码和响应头,同时也意味着告诉server
,application
要开始返回http的body了。这两个就是server
调用application
时候须要传递的全部参数了。
那么,咱们还须要再说一下,
environ
和start_response()
是须要在server
端的生成和定义的
有了这两个参数,application
就能知道用户请求的是什么资源,请求中带了什么数据,结果该如何返回给server
等等。其中,environ
包含了一些符合CGI规范的环境变量和WSGI规范新添加的变量,此外还可能有一些系统变量及Web服务器相关的环境变量。start_response
是一个可调用对象,它包含了一个表示HTTP响应状态的字符串和一个HTTP响应headers的列表以及一个用于出错返回的信息,具体参数包含及详情请点这里。
下面是一个完整的application demo,最终返回的body也能够是一个可迭代对象,这样server
也能够经过遍历这个对象来拼接成body。
def application(environ, start_response): start_response("200 OK", [("Content-type", "text/plain")]) return ["Hello World!",]
看上去不错,那么咱们该如何调用呢?
有几个服务器组件也可以运行的WSGI应用程序,可是对于简单的测试目的,咱们可使用包含在Python的标准库参考实现,就像下面那样:
if __name__ == '__main__': from wsgiref.simple_server import make_server server = make_server('localhost', 8080, application) server.serve_forever()
好了,还记得咱们刚才提到的最终返回的body也能够是一个可迭代对象吗?在python中,建立一个迭代器的简单办法就是使用一个生成器,好比,咱们有一个用于静态文件的服务,咱们能够写一个生成器,让它一次生成一个固定大小的文件块,这样咱们就能够随时一次只存储一个文件块了,让咱们来试试吧:
def send_file(file_path, size): with open(file_path) as f: block = f.read(BLOCK_SIZE) while block: yield block block = f.read(BLOCK_SIZE)
对应的 WSGI application 部分以下:
size = os.path.getsize(file_path) headers = [ ("Content-type", mimetype), ("Content-length", str(size)), ] start_response("200 OK", headers) return send_file(file_path, size)
注意,send_file
就是上文中所指的可迭代对象。
看得出来,WSGI应用结构很是简洁,只需指定一个可调用的识别标记,这使得WSGI应用很容易实现调用其余框架,无非就是修改到来的请求或者修改发出的响应,固然也能够二者都有。那么,接下来看看demo:
class Filter(object): def __init__(self, application): self.application = application def __call__(self, environ, start_response): # Do something here to modify request pass # Call the wrapped application app_iter = self.application(environ, self._sr_callback(start_response)) # Do something to modify the response body pass # Return modified response return app_iter def _sr_callback(self, start_response): def callback(status, headers, exc_info=None): # Do something to modify the response status or headers pass # Call upstream start_response start_response(status, headers, exc_info) return callback
像这样应用一般被称为Middleware applications或Filter。 Filter能够被链接在一块儿,由此产生的链一般被称为pipeline。
最后呢,我想说明一下,WSGI是故意设计成最小的Web服务器实现轻松的应用,以便被更多的人采用。可是,几乎没有人真的喜欢直接操做environ
变量,也几乎没有人喜欢用start_response
这么诡异的逻辑,虽然WSGI提供的API易于实现,但这不表明它的语义让人满意。也正是由于这一缘由,几乎每个应用程序或者web框架都把environ
和start_response
封装成了语义更完善容错率更高的request和response对象。
Webob就是request和response对象的规范实现之一,它使得WSGI更容易和更满意地被你们使用。
你能够在这里找到Webob的官方文档,固然,下次有机会我也会简单的说明一下Webob到底有多方便。