Python 的 WSGI 简单了解
从 flask 的 hello world 说起
直接讨论 WSGI,很多人可能没有概念,我们还是先从一个简单的 hello world 程序开始吧。
from flask import Flaskapp = Flask(__name__)@app.route("/", methods=['GET'])
def index():return "Hello world!"if __name__ == '__main__':app.run(port=8000)

相信只要使用过 flask 框架或者其它 Python 框架的人,应该都会见过这个警告。这个警告的意思是:这是一个开发服务器。不要在生产环境使用它。使用一个生产的 WSGI 服务器来代替。
那么什么是 WSGI 呢?
WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server communicates with web applications, and how web applications can be chained together to process one request.
WSGI 是 Web 服务器网关接口。它是一个规范,描述了web服务器如何与web应用程序通信,以及如何将web应用程序链接在一起以处理一个请求。
这里来看一个简略的时序图:
它描述了用户通过浏览器上网的过程,浏览器发送请求到 Server,Server 再把请求交给 Application 来处理,最后返回响应数据给用户的过程。(通常来说,请求在到达 Server 之前,还会先经过一个反向代理服务器,例如 nginx 或者 apache 等)

上面这个时序图其实可以看做是大部分网络应用程序的模式了。从请求到达应用和响应返回给用户,这个过程其实是固定的。所以,一个web应用的区别就在于它对请求的处理方式上,例如:用户使用百度、搜狗亦或是谷歌浏览器,对于用户的感知其实是相同的(尽管它们内部的实现并不相同,这里也不考虑用户的体验问题,哈哈)。
什么是 WSGI?
我们都知道通用的部分可以抽取出来,做成一个组件供其它应用使用。所以 WebServer 就是这样一个组件,它负责接收用户的请求,然后交给用户的Web应用,等到它处理完成之后,再把响应数据返回给调用者。所以,WebServer 要和 WebApplication 进行交互,那就需要定义一个协议或者更专业一点叫做接口,因此这就是 WSGI。而实现 WSGI 接口的,我们则成为 WebServer 或者 WSGI Server。
注:如果你有 java web 的背景,相信你应该使用过 tomcat,也听过 servlet API。其实,它们之间的关系和WSGI服务器与 WSGI接口的关系是类似的。
它的接口其实很简单,只要 Web 框架实现了它,就可以使用各种实现了 WSGI 接口的服务器了。

我们常用的 Web 框架有:falsk、django 等;WSGI 服务器有:gunicorn、uWSGI等。
对于我们入门学习来说,它其实也是很简单的,我们也不需要了解那么多。对于Web 框架的作者来说,他们需要提供一个带两个参数的可调用对象即可:
callable(environ, start_response)
下面是 Python 的 PEP3333 中提供的两个简单例子,一个是函数实现,一个是类实现,它们都是一个 Web Application。
HELLO_WORLD = b"Hello world!\n"def simple_app(environ, start_response):"""Simplest possible application object"""status = '200 OK'response_headers = [('Content-type', 'text/plain')]start_response(status, response_headers)return [HELLO_WORLD]class AppClass:"""Produce the same output, but using a class(Note: 'AppClass' is the "application" here, so calling itreturns an instance of 'AppClass', which is then the iterablereturn value of the "application callable" as required bythe spec.If we wanted to use *instances* of 'AppClass' as applicationobjects instead, we would have to implement a '__call__'method, which would be invoked to execute the application,and we would need to create an instance for use by theserver or gateway."""def __init__(self, environ, start_response):self.environ = environself.start = start_responsedef __iter__(self):status = '200 OK'response_headers = [('Content-type', 'text/plain')]self.start(status, response_headers)yield HELLO_WORLD
Python 官方提供了一个简单的 WSGI 实现,我们就以上面这两个例子为例来演示一下:
from wsgiref.simple_server import make_serverif __name__ == '__main__':with make_server("127.0.0.1", 8000, simple_app) as httpd:print("Server started on port 8000...")httpd.serve_forever()


使用基于类的实现,效果也是一样的,通常更推荐使用类的方式,因为可以利用面向对象的思想来编程。
from wsgiref.simple_server import make_serverif __name__ == '__main__':with make_server("127.0.0.1", 8000, AppClass) as httpd:print("Server started on port 8000...")httpd.serve_forever()
甚至,我们还可以再进行一步,使用这个 Python 自带的 WSGI 服务来运行最开始的 flask 的 hello world:
from wsgiref.simple_server import make_serverfrom flask import Flaskapp = Flask(__name__)@app.route("/", methods=['GET'])
def index():return "Hello world!"if __name__ == '__main__':with make_server("127.0.0.1", 8000, app) as httpd:print("Server started on port 8000...")httpd.serve_forever()
这样再次运行它,连警告也没有了。不过,自带的这个只是一个简单的实现,官方也并不推荐在生产环境使用它。但是 flask 其实并不知道,我们使用了什么 WSGI 服务器,因为它也不关心这个。


flask 背后的秘密
甚至不需要深入 flask 的源码,只需要浅浅的一探,我们就能明白为什么上面那样做的可以的了。这是 Flask 类的源码的一小部分,其它的无需解释了,我相信这是不言自明的。
class Flask(App):"""The flask object implements a WSGI application and acts as the centralobject. """def wsgi_app(self, environ: WSGIEnvironment, start_response: StartResponse) -> cabc.Iterable[bytes]:...def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> cabc.Iterable[bytes]:"""The WSGI server calls the Flask application object as theWSGI application. This calls :meth:`wsgi_app`, which can bewrapped to apply middleware."""return self.wsgi_app(environ, start_response)
总结
关于 WSGI,它的文档就直接说明了,对于 Web 开发者来说,其实并不用去了解它。因为我们的工作重点其实是请求的处理,对于我上面序列图中的大部分操作都不需要关系了,它隐藏了很多的细节,使得我们可以更加专注于自己的工作内容。不过,我觉得简单的了解一下也是蛮好的,也不需要深入的了解,浅尝辄止即可。对于我们工作的整个领域都有一个概览,然后还是专注于自己工作的重点内容上。
相关文章:
Python 的 WSGI 简单了解
从 flask 的 hello world 说起 直接讨论 WSGI,很多人可能没有概念,我们还是先从一个简单的 hello world 程序开始吧。 from flask import Flaskapp Flask(__name__)app.route("/", methods[GET]) def index():return "Hello world!&q…...
基于stm32使用ucgui+GUIBuilder开发ui实例
1 项目需求 1.1 基于Tft 触摸屏实现一个自锁按键 1.2 按键在按下后背景色需要进行变化,以凸显当前按键状态(选中or 未选中) 1.3 按键选中时对某一gpio输出低电平,非选中时输出高电平 2 移植 ucgui UCGUI的文件数量很大&#x…...
Spring扩展点系列-ApplicationContextAwareProcessor
文章目录 简介源码分析示例代码示例一:扩展点的执行顺序运行示例一 示例二:获取配置文件值配置文件application.properties内容定义工具类ConfigUtilcontroller测试调用运行示例二 示例三:实现ResourceLoaderAware读取文件ExtendResourceLoad…...
基于Keil软件实现实时时钟(江协科技HAL库)
实时时钟实验是基于江协科技STM32的HAL库工程模板创建的(可以在作品“基于江科大STM32创建的HAL库工程模板”中的结尾处获取工程模板的百度网盘链接) 复制“OLED显示”的工程文件——“4-1 OLED显示屏”,并命名为“12-2 实时时钟 ”。打开工程,把下面的程序复制到相应的文…...
dedecms靶场(四种webshell姿势)
进入靶场 姿势一:过文件管理器上传WebShell 步骤一:登录后台 /dede 步骤二:核心-》文件式管理-》文件上传-》上传一句话木马 点击 步骤三:进行蚁剑连接 姿势二:修改模板文件拿WebShell 步骤一:模板-》默认…...
PHP:强大的Web开发语言
PHP:强大的Web开发语言 一、PHP 简介及优势 PHP 的基本概念 PHP(PHP: Hypertext Preprocessor)即 “超文本预处理器”,是一种通用开源脚本语言,最初由 Rasmus Lerdorf 于 1994 年创建。它可以在服务器上执行…...
06_Python数据类型_元组
Python的基础数据类型 数值类型:整数、浮点数、复数、布尔字符串容器类型:列表、元祖、字典、集合 元组 元组(Tuple)是一种不可变的序列类型,与列表类似,但有一些关键的区别。本质:只读的列表…...
【Vue】- ref获取DOM元素和购物车案例分析
文章目录 知识回顾前言源码分析1. ref2. 购物车案例分析3. 购物车计算、全选 拓展知识数据持久化localStorage 总结 知识回顾 前言 元素上使用 ref属性关联响应式数据,获取DOM元素 步骤 ● 创建 ref > const hRef ref(null) ● 模板中建立关联 > <h1 re…...
【AI大模型】ChatGPT模型原理介绍(下)
目录 🍔 GPT-3介绍 1.1 GPT-3模型架构 1.2 GPT-3训练核心思想 1.3 GPT-3数据集 1.4 GPT-3模型的特点 1.5 GPT-3模型总结 🍔 ChatGPT介绍 2.1 ChatGPT原理 2.2 什么是强化学习 2.3 ChatGPT强化学习步骤 2.4 监督调优模型 2.5 训练奖励模型 2.…...
Python数据分析与可视化实战指南
在数据驱动的时代,Python因其简洁的语法、强大的库生态系统以及活跃的社区,成为了数据分析与可视化的首选语言。本文将通过一个详细的案例,带领大家学习如何使用Python进行数据分析,并通过可视化来直观呈现分析结果。 一、环境准…...
react18基础教程系列-- 框架基础理论知识mvc/jsx/createRoot
react的设计模式 React 是 mvc 体系,vue 是 mvvm 体系 mvc: model(数据)-view(视图)-controller(控制器) 我们需要按照专业的语法去构建 app 页面,react 使用的是 jsx 语法构建数据层,需要动态处理的的数据都要数据层支持控制层: 当我们需要…...
牛客周赛 Round 60 折返跑(组合数学)
题目链接:题目 大意: 在 1 1 1到 n n n之间往返跑m趟,推 m − 1 m-1 m−1次杆子,每次都向中间推,不能推零次,问有多少种推法(mod 1e97)。 思路: 一个高中学过的组合数…...
深入浅出Java匿名内部类:用法详解与实例演示
匿名内部类(Anonymous Inner Class)在Java中是一种非常有用的特性,它允许你在一个类的定义中直接创建并实例化一个内部类,而不需要为这个内部类指定一个名字。匿名内部类通常用于以下几种情况: 实现接口:当…...
数据库MySQL、Mariadb、PostgreSQL、MangoDB、Memcached和Redis详细介绍
以下是一些常见的后端开发数据库选型: 关系型数据库(RDBMS):关系型数据库是最常见的数据库类型,使用表格和关系模型来存储和管理数据。常见的关系型数据库包括MySQL、PostgreSQL和Oracle等。这些数据库适合处理结构化数…...
【ArcGIS Pro实操第七期】栅格数据合并、裁剪及统计:以全球不透水面积为例
【ArcGIS Pro实操第七期】批量裁剪:以全球不透水面积为例 准备:数据下载ArcGIS Pro批量裁剪数据集1 数据拼接2 数据裁剪3 数据统计:各栅格取值3.1 栅格计算器-精确提取-栅格数据特定值3.2 数据统计 4 不透水面积变化分析 参考 准备࿱…...
【Linux】Image、zImage与uImage的区别
1、Image 1.1 什么是 Image Image 是一种未压缩的 Linux 内核镜像文件,包含了内核的所有代码、数据和必要的元信息。它是 Linux 内核在编译过程中生成的一个原始的二进制文件,未经过任何压缩或额外的封装处理。由于未压缩,Image 文件相对较…...
算子加速(3):自定义cuda扩展
需要自定义某个层,或有时候用c++实现你的操作(c++扩展)可能会更好: 例如:需要实现一个新型的激活函数例如: bevfusion用cuda实现bevpool加速自定义扩展的步骤 (1) 首先用纯pytorch和python 实现我们所需的功能,看看效果再决定要不要进一步优化(2) 明确优化方向,用C++ (或CU…...
信息安全数学基础(14)欧拉函数
前言 在信息安全数学基础中,欧拉函数(Eulers Totient Function)是一个非常重要的概念,它与模运算、剩余类、简化剩余系以及密码学中的许多应用紧密相关。欧拉函数用符号 φ(n) 表示,其中 n 是一个正整数。 一、定义 欧…...
7-17 汉诺塔的非递归实现
输入样例: 3输出样例: a -> c a -> b c -> b a -> c b -> a b -> c a -> c 分析: 不会汉罗塔的uu们,先看看图解: 非递归代码: #include<iostream> #include<stack> using namespace std; s…...
word文档无损原样转pdf在windows平台使用python调用win32com使用pip安装pywin32
前提: windows环境下,并且安装了office套装,比如word,如果需要调用excel.也需要安装。在另外的文章会介绍。这种是直接调用word的。所以还原度会比较高。 需求: word文档转pdf,要求使用命令行形式,最终发布为api接口…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
