wsgi的定义
一个请求从客户端发到服务端,具体需要怎么样才能无缝对接呢?
在python中,服务端负责实际处理逻辑的有好几种,常见的也就是被大家所熟知的各个框架,如Django、Flask等。那请求经过怎样的处理进入到这些负责具体逻辑的框架呢?
那肯定不会是一个框架一个处理方式,那肯定是有规定好的一套逻辑,让各个框架来适配!
那就是WSGI协议:The Web Server Gateway Interface。
从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。
按照上面的描述,WSGI应该是单独实现的,和Django、Flask这些框架是隔离的。
实际上,的确有单独的,比如python下生产环境中经常用的WSGI容器Gunicorn。
但是呢,这些框架(包括以下提到的Odoo)都自己实现了WSGI协议——是自带Web服务器的。实现这些的目的是用于开发,生成环境还得用上面的。
也就是说,Django等框架分为WSGI容器和负责具体处理逻辑的部分,前者是不必要的。这点要认识清楚。
WSGI标准在PEP333中定义,后来在PEP3333中更新。它定义了在网络和python之间的沟通接口,一边连着Web服务器,一边连着具体的处理逻辑(后文统称应用或app)。对应用而言,它就是服务器程序,对服务器而言,它就是应用程序。
一张引用自参考4里的图:
wsgi示例图
wsgi规定的标准
WSGI对应用的规定:
- 应用(Application)必须是一个可调用(callable)对象。
- 这个可调用对象接受两个参数:environ(WSGI的环境信息,是个字典)和start_response(开始响应请求的函数)。
- 应用在返回前调用start_response。
- start_response也是可调用对象,接受两个参数:status(HTTP状态)和response_headers(响应头)。
- 应用要返回一个可迭代(iterable)对象。
例子:
def application(environ, start_response):
HELLO = 'hello world!'
status = '200 OK'
response_headers = [('Content-Type', 'text/plain'), ('Content-Length', len(HELLO))]
start_response(status, response_headers)
return [HELLO]
WSGI对服务器的规定:
- 准备environ和start_response。
- 调用应用。
- 迭代应用的返回结果,并将其通过网络传送至客户端。
例子:
import os, sys
def run_with_cgi(application):
environ = dict(os.environ.items())
headers = []
def write(data):
sys.stdout.write(data)
sys.stdout.flush()
def start_response(status, response_headers):
headers = [status, response_headers]
return write
result = application(environ, start_response)
try:
for data in result:
write(data)
finally:
if hasattr(result, 'close'):
result.close()