在用 Python web 开发时经常会遇到 WSGI, 所以 WSGI 到底是什么呢? 本文我们一起来揭开 WSGI 神秘的面纱!
先来看一下 WSGI 的介绍:
全称 Python Web Server Gateway Interface, 指定了 Web 服务器和 Python Web 应用或 Web 框架之间的标准接口, 以提高 Web 应用在一系列 Web 服务器间的移植性. 具体可查看 官方文档 https://www.python.org/dev/peps/pep-0333/
从以上介绍我们可以看出:
WSGI 是一套接口标准协议 / 规范;
通信 (作用) 区间是 Web 服务器和 Python Web 应用程序之间;
目的是制定标准, 以保证不同 Web 服务器可以和不同的 Python 程序之间相互通信
你可能会问, 为什么需要 WSGI?
首先, 我们明确一下 Web 应用处理请求的具体流程:
用户操作操作浏览器发送请求;
请求转发至对应的 Web 服务器
Web 服务器将请求转交给 Web 应用程序, Web 应用程序处理请求
Web 应用将请求结果返回给 Web 服务器, 由 Web 服务器返回用户响应结果
浏览器收到响应, 向用户展示
可以看到, 请求时 Web 服务器需要和 Web 应用程序进行通信, 但是 Web 服务器有很多种啊, Python Web 应用开发框架也对应多种啊, 所以 WSGI 应运而生, 定义了一套通信标准. 试想一下, 如果不统一标准的话, 就会存在 Web 框架和 Web 服务器数据无法匹配的情况, 那么开发就会受到限制, 这显然不合理的.
既然定义了标准, 那么 WSGI 的标准或规范是?
Web 服务器在将请求转交给 Web 应用程序之前, 需要先将 http 报文转换为 WSGI 规定的格式.
WSGI 规定, Web 程序必须有一个可调用对象, 且该可调用对象接收两个参数, 返回一个可迭代对象:
environ: 字典, 包含请求的所有信息
start_response: 在可调用对象中调用的函数, 用来发起响应, 参数包括状态码, headers 等
通过以上学习, 一起实现一个简单 WSGI 服务吧
首先, 我们编写一个符合 WSGI 标准的一个 http 处理函数:
- 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:
- # coding:utf-8
- """
- desc: WSGI 服务器实现
- """
- from wsgiref.simple_server import make_server
- from learn_wsgi.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 与 WSGI
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)
Flask 的 werkzeug 库是一个非常优秀的 WSGI 工具库, 具体的实现我们之后再详细学习.
以上.
来源: https://www.cnblogs.com/ybjourney/p/12004002.html