WSGI究竟是什么?

在用Python Web开发时常常会遇到WSGI,因此WSGI究竟是什么呢?本文咱们一块儿来揭开WSGI神秘的面纱!html

先来看一下WSGI的介绍前端

全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提升web应用在一系列web服务器间的移植性。 具体可查看 官方文档python

从以上介绍咱们能够看出:web

  1. WSGI是一套接口标准协议/规范;
  2. 通讯(做用)区间是Web服务器和Python Web应用程序之间;
  3. 目的是制定标准,以保证不一样Web服务器能够和不一样的Python程序之间相互通讯

你可能会问,为何须要WSGI?浏览器

首先,咱们明确一下web应用处理请求的具体流程:服务器

  1. 用户操做操做浏览器发送请求;
  2. 请求转发至对应的web服务器
  3. web服务器将请求转交给web应用程序,web应用程序处理请求
  4. web应用将请求结果返回给web服务器,由web服务器返回用户响应结果
  5. 浏览器收到响应,向用户展现

能够看到,请求时Web服务器须要和web应用程序进行通讯,可是web服务器有不少种啊,Python web应用开发框架也对应多种啊,因此WSGI应运而生,定义了一套通讯标准。试想一下,若是不统一标准的话,就会存在Web框架和Web服务器数据没法匹配的状况,那么开发就会受到限制,这显然不合理的。app

既然定义了标准,那么WSGI的标准或规范是?框架

web服务器在将请求转交给web应用程序以前,须要先将http报文转换为WSGI规定的格式。函数

WSGI规定,Web程序必须有一个可调用对象,且该可调用对象接收两个参数,返回一个可迭代对象:工具

  1. environ:字典,包含请求的全部信息
  2. 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工具库,具体的实现咱们以后再详细学习。

以上。

相关文章
相关标签/搜索