全称 Python Web Server Gateway Interface
,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。
从以上介绍我们可以看出:
首先,我们明确一下web应用处理请求的具体流程:
可以看到,请求时Web服务器需要和web应用程序进行通信,但是web服务器有很多种啊,Python web应用开发框架也对应多种啊,所以WSGI应运而生,定义了一套通信标准。试想一下,如果不统一标准的话,就会存在Web框架和Web服务器数据无法匹配的情况,那么开发就会受到限制,这显然不合理的。
web服务器在将请求转交给web应用程序之前,需要先将http报文转换为WSGI规定的格式。
WSGI规定,Web程序必须有一个可调用对象,且该可调用对象接收两个参数,返回一个可迭代对象:
首先,我们编写一个符合WSGI标准的一个http处理函数:
# client.py
def hello(environ, start_response):
status = "200 OK"
response_headers = [('Content-Type', 'text/html')]
start_response(status, response_headers)
path = environ['PATH_INFO'][1:] or 'hello'
return [b'<h1> %s </h1>' % path.encode()]
该方法负责获取 environ
字典中的 path_info
,也就是获取请求路径,然后在前端展示。
接下来,我们需要一个服务器启动WSGI服务器用来处理验证,使用Python内置的WSGI服务器模块 wsgiref
,编写server.py:
# server.py
from wsgiref.simple_server import make_server
from client import hello
def main():
server = make_server('localhost', 8001, hello)
print('Serving HTTP on port 8001...')
server.serve_forever()
if __name__ == '__main__':
main()
执行 python server.py
,浏览器打开 http://localhost:8001/a,即可验证。
通过实现一个简单的WSGI服务,我们可以看到:通过 environ
可以获取 http 请求的所有信息,http 响应的数据都可以通过 start_response
加上函数的返回值作为body。
当然,以上只是一个简单的案例,那么在python的Web框架内部是如何遵循WSGI规范的呢?以Flask举例,
Flask 中的程序实例 app
就是一个可调用对象,我们创建 app
实例时所调用的Flask类实现了 __call
方法,__call
方法调用了 wsgi_app()
方法,该方法完成了请求和响应的处理,WSGI服务器通过调用该方法传入请求数据,获取返回数据:
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)