作为 Python Web 开发者来说,在开发程序阶段一般是不会接触到 WSGI 这个名词的,但当程序开发完成,考虑上线部署的时候,WSGI 规范是一个绕不开的话题,本文将介绍何为 WSGI。

WSGI 全拼 Web Server Gateway Interface,是为 Python 语言定义的 Web 服务器和 Web 应用程序(或框架)之间的一种通用编程接口。翻译成白话就是说 WSGI 是一个协议,就像 HTTP 协议定义了客户端和服务端数据传输的规范,WSGI 协议定义了 Web 服务器和 Web 应用程序之间协同工作的规范。

Python Web 应用部署方案

Flask 或 Django 等 Web 框架都提供了内置的 Web Server,本地开发阶段可以使用 flask run 或 python manage.py runserver 来分别启动 Flask 或 Django 内置的 Server。

在生产环境部署应用时,通常不会使用框架内置的 Server,而是使用 Gunicorn 或 uWSGI 来部署,以获得更好的性能。部署过 Python Web 应用的同学应该对如下部署架构有所了解,左侧是浏览器,右侧是服务器。在服务器内部,首先通过 Nginx 来监听 80/443 端口,当接收到来自客户端的请求时,Nginx 会将请求转发到监听 5000 端口的 Gunicorn/uWSGI Server,接着请求会通过 WSGI 协议被传递到 Flask/Django 框架,在框架内部处理请求逻辑后,会将响应信息按照原路返回。

你可能会问,Nginx 性能很高,为什么不将应用直接部署到 Nginx 上,而是中间通过 Gunicorn/uWSGI 做一层转发呢?因为 Nginx 没有遵循 WSGI 规范,并不能像 Gunicorn/uWSGI 这样很容易的与 Flask/Django 框架结合起来。

WSGI 规范

根据 Python Web 应用部署架构,我们知道了 WSGI 所处的位置,接下来看下 WSGI 规范具体定义了哪些内容。

如同 HTTP 协议有一个客户端和一个服务端,WSGI 协议有一个 Application 端和一个 Server 端,其中 Application 就是指 Flask、Django 这些 Web 框架,而 Server 就是指 Gunicorn、uWSGI 等 Web 服务器。

WSGI 协议规定 Application 端需要实现成一个可调用对象(函数、类等),其接口如下:

def simple_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

simple_app 就是一个最简单的 Application,它需要接收两个参数,environ 是一个 dict,其中保存了所有 HTTP 请求相关的信息,由 Server 端提供,start_response 是一个可调用对象,同样由 Server 端提供,simple_app内部需要调用一次 start_response,并将 状态码 和 响应头 当作参数传递给它,simple_app 最终会返回一个可迭代对象作为 HTTP Body 内容返回给客户端。

我们已经知道了 Application 端接口,接下来看下一个符合 WSGI 协议的 Server 端实现:

import os


def wsgi_server(application):
    environ = dict(os.environ.items())

    def start_response(status, response_headers):
        print(f'status: {status}')
        print(f'response_headers: {response_headers}')

    result = application(environ, start_response)
    for data in result:
        print(f'response_body: {data}')

示例中 Server 端同样使用函数来实现,wsgi_server 接收一个 application 作为参数,在其内部构造了 environ 和 start_response 两个对象,这里使用环境变量信息来模拟 HTTP 请求信息构造 environ 字典,start_response 同样被定义为一个函数,供 application 在内部对其进行调用,wsgi_server 函数最后会调用 application 并对其进行打印。

现在有了 Application 端和 Server 端,我们可以来测试一下这个简单的 WSGI 程序示例。只需要将 simple_app 作为参数传递给 wsgi_server 并调用 wsgi_server 即可:

wsgi_server(simple_app)

执行以上代码,将得到如下打印:

status: 200 OK
response_headers: [('Content-type', 'text/plain')]
response_body: Hello world!

以上,我们分别实现了符合 WSGI 规范的 Application 端和 Server 端,虽然程序看起来比较简陋,但不论多么复杂的 Python Web 框架和 Server 都同样遵循此规范。

WSGI 实际应用

学习了 WSGI 规范,我们可以来验证下平时使用的 Python Web 框架是否真的遵循此规范,这里以 Flask 框架源码为例,可以在 https://github.com/pallets/flask/blob/master/src/flask/app.py 查看 Flask 的定义:

class Flask(Scaffold):
    ...

    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app`, which can be
        wrapped to apply middleware.
        """
        return self.wsgi_app(environ, start_response)

Flask 类内部通过实现 __call__ 方法,使得 Flask 实例对象成为一个可调用对象,其接口实现同样符合 WSGI Application 规范。

以上就是Python WSGI 规范简介的详细内容,更多关于Python WSGI 规范的资料请关注程序员的世界其它相关文章!

Python WSGI 规范简介的更多相关文章

  1. python里glob模块知识点总结

    之前遇到过一类问题,要求快速做文件搜索,当时小编找了很多内容,但是没有发现实现方法,突然看到glob模块便豁然开朗了,该模块主要就是能够实现类似于windows的文件搜索,旗下的函数都可以实现搜索功能,并且有很多通配符,能够应用在多种场景中,一一对应的选择解决方案。简单介绍:匹配一定的格式文件和文件......

  2. python函数指定默认值的实例

    1、说明(1)写函数时,可以为每个参数指定默认值。当调用函数为参数提供实际参数时,Python将使用指定的实际参数;否则,将使用参数的默认值。因此,给参数指定默认值后,可以在函数调用中省略相应的参数。(2)使用默认值可以简化函数调用,明确指出函数的典型用法。2、实例>>> def ......

  3. Python读写Excel表格的方法

    本文实例为大家分享了Python读写Excel表格的具体代码,供大家参考,具体内容如下python读取Excel表格:import xlrd def read_excel():# 打开文件wb = xlrd.open_workbook(r'test.xls')# 获取所有sheet的名字print(......

  4. Python获取百度热搜的完整代码

    好久没写了,就把上课做的一个小东西拿出来分享一下吧。百度网页截图如下 ↓↓↓程序运行输出结果截图 ↓↓↓上代码 ↓↓↓from lxml import etreefrom lxml import htmlimport requestsheaders={'User-Agent':'Mozilla/5.......

  5. pandas 颠倒列顺序的两种解决方案

    在数据预处理过程中可能需要将列的顺序颠倒,有两种方法。import numpy as npimport pandas as pddf = pd.DataFrame(np.array(range(20)).reshape(4,5))print(df)原始dataframe如下:0 1 2 3 ......

  6. Pytorch数据读取与预处理该如何实现

    在炼丹时,数据的读取与预处理是关键一步。不同的模型所需要的数据以及预处理方式各不相同,如果每个轮子都我们自己写的话,是很浪费时间和精力的。Pytorch帮我们实现了方便的数据读取与预处理方法,下面记录两个DEMO,便于加快以后的代码效率。根据数据是否一次性读取完,将DEMO分为:1、串行式读取。也就......

  7. 使用bandit对目标python代码进行安全函数扫描

    本文介绍了python安全危险函数扫描工具bandit的数种使用方法与技巧,同时也分析了bandit在实际项目中的性能表现,给予了读者是否在python开发项目中引入bandit的启发思考。技术背景在一些对python开源库代码的安全扫描中,我们有可能需要分析库中所使用到的函数是否会对代码的执行环境......

  8. Python爬取科目四考试题库的方法实现

    1、环境PyCharmPython 3.6pip安装的依赖包包括:requests 2.25.0、urllib3 1.26.2、docx 0.2.4、python-docx 0.8.10、lxml 4.6.2谷歌浏览器2、目标网站及请求分析驾驶员考试网站 ......

  9. Python爬虫scrapy框架Cookie池(微博Cookie池)的使用

    下载代码Cookie池(这里主要是微博登录,也可以自己配置置其他的站点网址)下载代码GitHub:https://github.com/Python3WebSpider/CookiesPool下载安装过后注意看网页下面的相关基础配置和操作!!!!!!!!!!!!!自己的设置主要有下面几步:1、配置其......

  10. python删除csv文件的行列

    1. 读取数据用pandas中的read_csv()函数读取出csv文件中的数据:import pandas as pddf = pd.read_csv("comments.csv")df.head(2)用drop函数进行文件中数据的删除行或者删除列操作。2. 删除列操作方法一:......

随机推荐

  1. 手把手教你搭建SSH框架(Eclipse版)

    原文来自公众号【C you again】,若需下载完整源码,请在公众号后台回复“ssh”。本期文章详细讲解了SSH(Spring+SpringMVC+Hibernate)框架的搭建过程,语言简洁、通俗易懂,适合初级程序员阅读。在开始教程之前,先来了解SSH框架的基本概念:在文章《手把手教你搭建SSM......

  2. Python Pandas提取单元格的值操作

    如提取第1行,第2列的值:df.iloc[[0],[1]]则会返回一个df,即有字段名和行号。如果用values属性取值:df.iloc[[0],[1]].values返回的值会是列表,而且是嵌套列表:[[值]]因此,正确的写法是:df.iloc[[0],[1]].values[0][0]补充:pa......

  3. C# 中的动态类型

    翻译自 Camilo Reyes 2018年10月15日的文章 《Working with the Dynamic Type in C#》 [1].NET 4 中引入了动态类型。动态对象使您可以处理诸如 JSON 文档之类的结构,这些结构的组成可能要到运行时才能知道。在本文中,Camilo Reye......

  4. spring使用RedisTemplate操作Redis数据库

    一.什么是RedisRedis是一个非关系型数据库,具有很高的存取性能,一般用作缓存数据库,减少正常存储数据库的压力。Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。下面......

  5. Java压缩集合的三种方法

    前言这个问题算是开发当中偶尔会遇到的一个小问题,比如如何将两个集合压缩成为一个逻辑集合。如果你不理解,我们可以看一个简单的例子,去说明什么是压缩集合。本文文章不长,但是还算是比较实用的小技巧。主要内容来源于国外小哥Baeldung的博客:下面给出个地址https://www.baeldung.com......

  6. Wi-Fi 6 与 5G 相比哪个更快?

    随着 iPhone12 的发布,iOS 系统正式开始拥抱 5G,智能手机全面进入了 5G 时代。伴随着各大运营商的 5G 推广以及相关基站建设的如火如荼,5G 成了大家广泛讨论的热门词汇。这样热门的光芒让其他新词汇不得不退让并离开大家的视野,然而有另一项新技术却悄悄登场并且完成了属于自己的市场迭代,......

  7. 用python写个博客迁移工具

    前言最近不少写博客的朋友跟我反馈博客园的一些文章下架了,这让我联想到去年简书一样,我之前写的博客都被下架不可见了。我最开始接触的博客网址是 csdn、思否、简书还有博客园等,但是后期发现,单论博客的生态感觉做的越来越不行,干货虽然很多,但是垃圾、标题党很严重,我自己也有一些博文被莫名的搬走直接标为原......

  8. R语言 数据集行列互换的技巧分享

    现在给大家介绍的数据处理技巧是长转宽,也就相当于Excel中的转置,不过用R语言实现的长转宽还有数据合并的功能,自然比Excel强大多了。这里给大家介绍4个函数,其中melt()、dcast()来自reshape2包,gather()、spread()来自tidyr包一、宽转长——melt()、ga......

  9. Oracle 常用命令大全(持续更新)

    数据库----数据库启动 & 关闭启动数据库SQL> startup nomount;SQL> alter database mount;SQL> alter database open; 关闭数据库SQL> shutdown immediate; 更多内容请参考:O......

  10. R语言关于“包”的知识点总结

    R语言的包是R函数,编译代码和样本数据的集合。 它们存储在R语言环境中名为“library”的目录下。 默认情况下,R语言在安装期间安装一组软件包。 随后添加更多包,当它们用于某些特定目的时。 当我们启动R语言控制台时,默认情况下只有默认包可用。 已经安装的其他软件包必须显式加载以供将要使用它们的R......