(十五)Flask覆写wsgi_app函数实现自定义中间件

2023-12-07 21:44

本文主要是介绍(十五)Flask覆写wsgi_app函数实现自定义中间件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

中间件

一、剖析:

在前面讲session部分提到过:请求一进来,Flask会自动调用应用程序对象【Flask(__name__)】的__call__方法,这个方法负责处理请求并返回响应(其实如下图:其内部就是wsgi_app方法)。它是WSGI规范所要求的。

在这里插入图片描述

wsgi_app方法内部,Flask会根据路由规则和视图函数来确定如何处理请求,并生成相应的响应。最终,wsgi_app方法会将响应返回给Web服务器,供其发送给客户端(前面详细讲过,后面还会再细细剖析)。

所以,这里就有一个坑可以让我们操作,即我们可以通过覆写wsgi_app方法,实现自己的中间件逻辑,例如身份验证、日志记录等。

而且这个坑牛逼之处在于:我们可以借由它实现在最开始的开始和最后的最后做操作!!!多加理解,底下会详细讲解。

结合实战讲解—通过覆写wsgi_app函数实现一个简单的中间件:

from flask import Flaskapp = Flask(__name__)class MyMiddleware:def __init__(self, old_wsgi_app):# 服务端启动时,自动执行self.old_wsgi_app = old_wsgi_appdef __call__(self, environ, start_response):# 每次有用户请求到来时执行# 在请求到达视图函数之前执行的代码print("Before request")# 调用原始的wsgi_app函数处理请求response = self.old_wsgi_app(environ, start_response)# 在响应发送给客户端之前执行的代码print("After request")return response@app.route('/')
def home():return "Hello, GuHanZhe~"# 设置自定义中间件实例为应用程序对象的wsgi_app属性
app.wsgi_app = MyMiddleware(app.wsgi_app)if __name__ == '__main__':app.run()

在上述示例中,我定义了一个名为MyMiddleware的类,它接受一个Flask应用程序对象的wsgi_app方法作为参数。该类实现了__call__方法,这是一个wsgi应用程序必须具备的方法。在__call__方法中,大家可以编写自己的中间件逻辑。

__call__方法中,大家可以首先执行在请求到达视图函数之前需要执行的代码,然后调用原始的wsgi_app方法处理请求,并将响应保存在response变量中。最后,在响应发送给客户端之前,大家可以执行一些在响应阶段需要执行的代码。

通过创建自定义中间件实例,并将其设置为Flask应用程序对象的wsgi_app属性,就可以使用自定义的中间件了。

请注意,自定义中间件类必须实现__call__方法,并且接受environstart_response参数,这是遵守WSGI规范。

而且看Flask的wsgi_app函数源码,也是如此:

在这里插入图片描述

需要注意的是:在print("Before request")部分做操作时,只有原生的请求相关的数据environ,所以就只能对原生的environ做操作! request和session是都没有的!!!

二、应用点:

通过覆写wsgi_app函数实现的自定义中间件可以有如下几种在开发时的应用点:

  1. 可以对请求进行预处理:通过覆写wsgi_app函数,可以在请求到达视图函数之前执行一些代码逻辑,例如身份验证、参数解析、请求日志记录等。这样可以方便地对请求进行预处理,并根据需要做出相应的处理。

  2. 可以对响应进行后处理:同样地,在覆写wsgi_app函数时,还可以在响应发送给客户端之前执行一些代码逻辑,例如响应的加工、错误处理、响应日志记录等。这样可以方便地对响应进行后处理,以满足特定的需求。

  3. 可以实现自定义中间件功能:通过覆写wsgi_app函数,可以实现自定义的中间件功能。中间件是一种可重用的组件,可以用于添加额外的逻辑或修改请求/响应的行为。可以根据具体需求编写自己的中间件,并将其插入Flask应用程序对象的处理流程中。

  4. 可以实现多个中间件的串联:Flask允许使用多个中间件,并且这些中间件可以按照特定的顺序串联起来。通过覆写wsgi_app函数,可以轻松地将多个中间件组合起来,形成一个中间件链条。每个中间件都可以独立地处理请求和响应,并将处理结果传递给下一个中间件。

  5. 可以修改请求和响应:通过覆写wsgi_app函数,可以自由地修改请求和响应对象。这包括添加、删除或修改请求头部信息,修改请求体内容,修改响应状态码,添加响应头部信息等。这样可以实现更加灵活和定制化的请求/响应处理。

总而言之,覆写wsgi_app函数实现中间件提供了对请求和响应进行预处理和后处理的能力,同时也允许编写自定义的中间件功能。这样可以增强Flask应用程序的功能和灵活性,满足特定的需求。

就比如要做IP黑名单,就可以在before里直接写逻辑(environ里有请求IP信息),这样就可以在最开始的开始直接限制!

拓展:

(1)在Python中,当一个对象后面能加括号,那么这个对象可能是什么?

  1. 函数:一个函数是可调用的对象。通过在函数名后加上括号,可以执行该函数并传递相应的参数。

  2. 方法:方法是属于类的函数。通过在实例或类名后加上括号,可以调用该方法并传递相应的参数。

  3. 类:类本身也是可调用的对象。通过在类名后加上括号,可以创建类的实例。

  4. 对象:某个类的实例对象也可以是可调用的对象。通过在对象名后加上括号,可以调用该对象所属类中定义的特殊方法,例如__call__()方法。

(2)在Python中,函数和方法分别是什么?

首先,要认识到在Python中,函数(function)和方法(method)是两种不同的概念。这也是为啥我给的问题是“函数和方法分别是什么?”

  1. 函数(function)是一段封装了特定功能的可重用代码块。它接收输入参数,执行特定的操作,并返回结果。 函数可以在任何地方定义和使用,不依赖于任何类或对象。它们通常用于模块化代码、提高代码的复用性和可维护性。

    例如,下面是一个简单的函数示例:

def add(a, b):return a + bresult = add(2, 3)
print(result)  
  1. **方法(method)是属于某个类的函数。**它定义在类的内部,并且可以访问类的属性和其他方法。**方法通过对类的实例进行调用来执行相应的操作。**每个方法的第一个参数通常都是 self,它表示方法所属的实例对象。

    例如,下面是一个简单的类和方法示例:

class Circle:def __init__(self, radius):self.radius = radiusdef area(self):return 3.14 * self.radius * self.radiuscircle = Circle(5)
circle_area = circle.area()
print(circle_area)  # 输出:78.5

在上面的示例中,area()Circle 类的一个方法,它可以通过 circle.area() 的方式进行调用。

需要注意的是,对于一个类里面的函数,它究竟真是函数还是方法,取决于谁调用它!!!

举个例子:

在这里插入图片描述

上图中Test.index执行的话,此时index作为函数,意思是执行类里面的函数;

而下面是通过类的实例调用,所以此时是方法。

或者这样也能证明:

from types import MethodType, FunctionTypeclass Test(object):def index(self):pass# print(Test.index)
print(isinstance(Test.index, FunctionType))test = Test()
# print(test.index)
print(isinstance(test.index, MethodType))

在这里插入图片描述

总结:函数是独立的可调用代码块,而方法是属于类的函数,需要通过类的实例进行调用。

这篇关于(十五)Flask覆写wsgi_app函数实现自定义中间件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/467461

相关文章

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

MySQL count()聚合函数详解

《MySQLcount()聚合函数详解》MySQL中的COUNT()函数,它是SQL中最常用的聚合函数之一,用于计算表中符合特定条件的行数,本文给大家介绍MySQLcount()聚合函数,感兴趣的朋... 目录核心功能语法形式重要特性与行为如何选择使用哪种形式?总结深入剖析一下 mysql 中的 COUNT

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

MySQL 中 ROW_NUMBER() 函数最佳实践

《MySQL中ROW_NUMBER()函数最佳实践》MySQL中ROW_NUMBER()函数,作为窗口函数为每行分配唯一连续序号,区别于RANK()和DENSE_RANK(),特别适合分页、去重... 目录mysql 中 ROW_NUMBER() 函数详解一、基础语法二、核心特点三、典型应用场景1. 数据分

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景