wsgi是什么
- wsgi(Web Server Gateway Interface)web服务器网关接口,是一套在httpserver(比如nginx,apache)和python程序之间传递的接口标准,WSGI 是基于现存的 CGI 标准而设计的.
- wsgi在PEP333中定义
- WSGI 的设计参考了 Java 的 servlet
- python 中,作为wsgi服务器的组件有uwsgi,gunicorn等。
- 常见的http请求的处理流程如下所示:
Nginx-->(wsgi)gunicorn-->framework-->application
wsgi工作在wsgi服务器和web服务器的中间,一般是使用nginx来进行反向代理。然后使用gunicorn来当wsgi服务器。
其中,nginx一般用作负载均衡处理,gunicorn用于http请求的解析和封装,为framework提供梳理好的http数据。而application则用于根据框架请求的数据进行相应的处理。
wsgi的规范:
- wsgi规定每个 python 程序(Application)必须是一个可调用的对象(实现了_call_ 函数的方法或者类),接受两个参数
environ
(WSGI 的环境信息) 和start_response
(开始响应请求的函数),并且返回 iterable
其中:
- environ 和 start_response 由 http server 提供并实现
- environ 变量是包含了环境信息的字典
- Application 内部在返回前调用 start_response
- start_response也是一个 callable,接受两个必须的参数,status(HTTP状态)和 response_headers(响应消息的头)
- 可调用对象要返回一个值,这个值是可迭代的。
2:
wsgi实现:
wsgi 应用端实现:
# 1. 可调用对象是一个函数
def application(environ, start_response):
response_body = 'The request method was %s' % environ['REQUEST_METHOD']
# HTTP response code and message
status = '200 OK'
# 应答的头部是一个列表,每对键值都必须是一个 tuple。
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
# 调用服务器程序提供的 start_response,填入两个参数
start_response(status, response_headers)
# 返回必须是 iterable
return [response_body]
# 2. 可调用对象是一个类
class AppClass:
"""这里的可调用对象就是 AppClass 这个类,调用它就能生成可以迭代的结果。
使用方法类似于:
for result in AppClass(env, start_response):
do_somthing(result)
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
# 3. 可调用对象是一个实例
class AppClass:
"""这里的可调用对象就是 AppClass 的实例,使用方法类似于:
app = AppClass()
for result in app(environ, start_response):
do_somthing(result)
"""
def __init__(self):
pass
def __call__(self, environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
wsig是处于web server 和web application中间的一层,所以
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()
参考连接:
wsgi PEP333翻译
WSGI协议的原理及实现