所有的Python web框架都需要WSGI协议,所以要深入了解一个web框架,很有必要去了解下WSGI;
WSGI(Web Server Gateway Interface) 的任务就是把上面的数据在 http server 和 python 程序之间简单友好地传递。它是一个标准,被定义在PEP 333。需要 http server 和 python 程序都要遵守一定的规范,实现这个标准的约定内容,才能正常工作。
图片出处
WSGI Application端
application端定义非常简单,它只要求开发者实现一个函数来响应HTTP请求。
这个函数就是一个符合WSGI标准的一个HTTP处理函数,它接收两个参数:
-
environ
: 一个包含所有HTTP请求信息的dict
对象。 -
start_response
: 一个发送HTTP响应的函数,这个函数接受两个参数,一个是HTTP响应码,一个是HTTP header。
# wsgi_client.py
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ["hello world"]
WSGI Server端
envrion
和start_response
这两个参数由服务端提供,PEP333里给出了一个wsgi server的简单实现:
import os, sys
def run_with_cgi(application): # application 是程序端的可调用对象
# 准备 environ 参数,这是一个字典,里面的内容是一次 HTTP 请求的环境变量
environ = dict(os.environ.items())
environ['wsgi.input'] = sys.stdin
environ['wsgi.errors'] = sys.stderr
environ['wsgi.version'] = (1, 0)
environ['wsgi.multithread'] = False
environ['wsgi.multiprocess'] = True
environ['wsgi.run_once'] = True
environ['wsgi.url_scheme'] = 'http'
headers_set = []
headers_sent = []
# 把应答的结果输出到终端
def write(data):
sys.stdout.write(data)
sys.stdout.flush()
# 实现 start_response 函数,根据程序端传过来的 status 和 response_headers 参数,
# 设置状态和头部
def start_response(status, response_headers, exc_info=None):
headers_set[:] = [status, response_headers]
return write
# 调用客户端的可调用对象,把准备好的参数传递过去
result = application(environ, start_response)
# 处理得到的结果,这里简单地把结果输出到标准输出。
try:
for data in result:
if data: # don't send headers until body appears
write(data)
finally:
if hasattr(result, 'close'):
result.close()
或者,python中也内置了一个WSGI服务器模块wsgiref
, 通过这个模块就可以快速实现了个WSGI Server来测试我们的application
:
# wsgi_server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
import wsgi_client
# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, wsgi_client.application)
print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()
可以看到结果为wsgi_client.py
中定义的hello world
Flask框架中的一个核心库werkzeug其实就是Python的WSGI规范的实用函数库