(十三)Flask之特殊装饰器详解

目录:

  • Flask中用作装饰器的特殊的函数
    • 第一部分:`before_request`和`after_request`
      • 一、 `before_request`装饰器:
      • 二、`after_request`装饰器:
      • 三、多个`before_request`和`after_request`执行流程分析:
        • 首先—理论讲解:
        • 然后—实战讲解:
        • 最后—扒扒源码:
        • 画图形象记忆:
    • 第二部分:实战—使用`before_request`进行身份验证
    • 第三部分:补充常见特殊装饰器
      • 一、`@app.errorhandler(code)`:
      • 二、 `@app.teardown_request`:
      • 三、`@app.template_test`:
      • 四、`@app.before_first_request`:

Flask中用作装饰器的特殊的函数

第一部分:before_requestafter_request

在Flask中,before_requestafter_request是用作装饰器的特殊函数,它们可以用来在请求处理过程中执行某些操作。

一、 before_request装饰器:

  • 通过在函数上使用@app.before_request装饰器,可以将该函数注册为全局的请求前钩子(hook)。这意味着每次请求到达服务器时,在实际处理请求之前,都会先执行被before_request装饰的函数。
  • before_request函数通常用于执行一些预处理任务,例如验证用户身份、设置全局变量、打开数据库连接等。它可以修改请求或应用程序上下文,并且可以返回响应对象或 None(后面扒扒源码看看)。

比如:

@app.before_request
def before_request():
    # 执行一些预处理任务
    if not current_user.is_authenticated:
        return redirect(url_for('login'))

二、after_request装饰器:

  • 通过在函数上使用@app.after_request装饰器,可以将该函数注册为全局的请求后钩子。这意味着在每次请求完成并返回响应之后,都会执行被after_request装饰的函数。

  • after_request函数通常用于执行一些后处理任务,例如**添加响应头、记录请求日志、关闭数据库连接等。**它接收一个参数,即响应对象,并且必须返回一个响应对象。

比如:

@app.after_request
def after_request(response):
    # 执行一些后处理任务
    response.headers['X-Frame-Options'] = 'SAMEORIGIN'
    return response

通过使用before_requestafter_request装饰器,可以在请求的前后执行一些共同的逻辑,从而实现全局的预处理和后处理操作。这样可以避免在每个视图函数中重复编写相同的代码。

三、多个before_requestafter_request执行流程分析:

首先—理论讲解:

当存在多个before_requestafter_request装饰器时,分析它们的执行顺序:

  1. before_request执行流程:

    • 当一个请求到达服务器时,首先会执行第一个注册before_request装饰的函数。
    • 如果该函数返回了一个响应对象,则停止执行后续所有的before_request函数,而是直接返回该响应对象给客户端。
    • 如果该函数没有返回响应对象,则继续执行下一个注册的before_request函数,以此类推,直到所有的before_request函数都被执行完毕。
  2. after_request执行流程:

    • 在每次请求完成并返回响应之后,从最后一个注册after_request装饰的函数开始执行。
    • 每个after_request函数都会接收前一个after_request函数所返回的响应对象作为参数,并且必须返回一个新的响应对象。
    • 执行完最后一个after_request函数后,最终的响应对象将会发送给客户端。
然后—实战讲解:
from flask import Flask, session

app = Flask(__name__)  # 创建Flask应用程序对象


@app.before_request
def before_request_1():
    print("Before Request 1")


@app.before_request
def before_request_2():
    print("Before Request 2")


@app.after_request
def after_request_1(response):
    print("After Request 1")
    return response


@app.after_request
def after_request_2(response):
    print("After Request 2")
    return response


@app.route('/')
def index():
    print("Index Page")
    return "Hello, World!"


if __name__ == '__main__':
    app.run()

输出的执行顺序如下:

在这里插入图片描述

可以看到,首先执行了before_request_1before_request_2两个函数,然后处理了请求并返回响应,接着按照相反的顺序执行了after_request_2after_request_1两个函数。

最后—扒扒源码:

为何before_request是按注册顺序执行,而after_request是按注册倒序执行嘞?

扒一扒源码就晓得啦~

直接进入before_requestafter_request的身体:

在这里插入图片描述

上面就是Flask注册before_requestafter_request函数的方法,一模一样!

下面来扒下Flask执行before_requestafter_request函数部分的源码:

进入app.__call__()后直到full_dispatch_request函数:

在这里插入图片描述

在这里插入图片描述

关注点先放在上图第二个for循环,其余部分后续会慢慢探究~

before_request_funcs 就是上述包含了请求前钩子函数的字典。这些函数会在请求分发(即dispatch_request)之前被调用。

遍历每个注册的请求前钩子函数,并执行它们。如果任何一个请求前钩子函数**返回一个非 None 的值,该值会被当作视图函数的返回值处理(直接返回给客户端页面),并且后续的请求处理流程会被停止【但是after_request正常执行!】;**如果没有任何请求前钩子函数返回非 None 值,那么 preprocess_request 方法会返回 None。

来个代码讲解:

在这里插入图片描述
在这里插入图片描述

画图形象记忆:

绿色就是所有请求前钩子函数(before_request)返回值都为None时的执行流程;

相应的,白色就是有一个返回值非None时的执行流程。
在这里插入图片描述

差点忘了带大家看after_request了!

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

看到没!reversed!!!反向遍历哦~

第二部分:实战—使用before_request进行身份验证

上代码:

from flask import Flask, request, redirect, url_for, render_template, session

app = Flask(__name__)

# 模拟的用户数据库
users = {
    'admin': {
        'username': 'admin',
        'password': 'GuHanZhe'
    }
}


@app.before_request
def authenticate_user():
    # 获取当前请求的路径
    path = request.path

    # 如果请求的路径不是登录页面,进行身份验证
    if path != '/login':
        # 检查 session 中是否存在已登录的用户
        if 'username' not in session:
            # 用户未登录,重定向到登录页面
            return redirect(url_for('login'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']

        # 在实际开发中,这里需要进行密码验证
        if username in users and users[username]['password'] == password:
            # 登录成功,将用户名保存在 session 中
            session['username'] = username
            return redirect(url_for('protected_page'))
        else:
            # 登录失败,显示错误信息
            error_message = "Invalid username or password."
            return render_template('login.html', error_message=error_message)

    return render_template('login.html')


@app.route('/protected')
def protected_page():
    return "This is a protected page. Only logged-in users can access it."


if __name__ == '__main__':
    app.run()

在上述代码中,before_request 钩子函数 authenticate_user 用于验证用户身份。它会在每个请求到达之前被调用,除了登录页面 /login 外的所有页面都需要进行身份验证。

如果用户未登录,authenticate_user 函数将重定向到登录页面,使用 redirect 函数和 url_for 函数实现页面重定向。登录成功后,将用户名保存在 session 中,以便在后续的请求中进行验证。

login 路由处理函数负责渲染登录页面,并接收用户提交的表单数据。在实际应用中,需要根据数据库中的用户信息进行密码验证。验证成功后,将用户名保存在 session 中,并重定向到受保护的页面 /protected

protected_page 路由处理函数是一个示例的受保护页面,只有登录用户可见。

第三部分:补充常见特殊装饰器

一、@app.errorhandler(code)

  • 这是用于注册错误处理函数的装饰器。
  • code 参数指定了需要处理的错误码,例如 404、500 等。
  • 装饰的函数将作为错误处理函数,在出现指定错误码时被调用,并返回自定义的错误页面或响应。

二、 @app.teardown_request

用于注册在每个请求结束时执行的函数。它可以用来进行一些清理操作或释放资源。

实战:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return "Hello, World!"


@app.teardown_request
def teardown_request_func(error=None):
    print("Teardown function is called after each request.")


if __name__ == '__main__':
    app.run()

在上述代码中,定义了一个名为 teardown_request_func 的函数,并使用 @app.teardown_request 装饰器将其注册为每个请求结束时执行的函数。

当我们访问任何路由时,Flask 会在请求结束后自动调用 teardown_request_func 函数。无论请求是否出现错误,该函数都会被执行。

需要注意的是,@app.teardown_request 装饰的函数只能接受一个参数,即可选的错误对象。如果要访问请求上下文中的其他对象,可以使用 flask.request 对象。

这个装饰器通常用于进行一些清理操作,例如关闭数据库连接、释放资源等。

三、@app.template_test

用于注册自定义模板测试函数的装饰器。

实战:

from flask import Flask

app = Flask(__name__)


@app.template_test('even')
def is_even(number):
    return number % 2 == 0


if __name__ == '__main__':
    app.run()

通过 @app.template_test('even') 装饰器将 is_even 函数注册为一个名为 “even” 的模板测试函数。该函数用于判断一个数字是否是偶数。

在模板中,可以使用 {% if %} 语句来调用这个模板测试函数:

{% if num is even %}
    <p>The number is even</p>
{% else %}
    <p>The number is odd</p>
{% endif %}

通过注册模板测试函数,我们可以在模板中使用自定义的逻辑判断函数,以便根据特定的条件进行动态渲染和显示不同的内容。

四、@app.before_first_request

用于注册在第一个请求到达之前执行的函数。它只会在应用程序启动时执行一次。

实战:

from flask import Flask

app = Flask(__name__)


@app.before_first_request
def before_first_request_func():
    print("This function is executed before the first request.")


@app.route('/')
def index():
    return "Hello, World!"


if __name__ == '__main__':
    app.run()

在上述代码中,before_first_request_func 被装饰为 @app.before_first_request,它会在第一个请求到达之前执行。

当我们运行这个应用程序时,before_first_request_func 函数会在第一个请求到达之前执行一次。之后,每个请求到达时,都不会再次调用该函数。

需要注意的是,@app.before_first_request 装饰的函数仅在主线程中执行,并且只有在应用程序启动时才会被调用一次。如果使用多线程或多进程部署应用程序,可以考虑使用其他方法来进行初始化操作。

【新版本Flask没有这个装饰器了~】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/193103.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新AI创作系统ChatGPT网站运营源码、支持GPT-4-Turbo模型,图片对话识图理解,支持DALL-E3文生图

一、AI创作系统 SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01;本系统使用NestjsVueTypescript框架技术&#xff0c;持续集成AI能力到本系统。支持OpenAI DALL-E3文生图&#xff0c;…

PCB板的固螺丝孔连接电阻电容有什么好处

PCB板的固螺丝孔连接电阻电容有什么好处 并联高压电容和大电阻作用好处个人经历看法 并联高压电容和大电阻 我们经常会看到一些系统设计中将PCB板的地(GND)与金属外壳(EGND)之间通常使用一个高压电容C1&#xff08;1~100nF/2KV&#xff09;并联一个大电阻R1&#xff08;1M&…

Java PriorityQueue

一般情况下, 我们使用队列是为了能够建造队列的先进先出 (First-In-First-Out) 模式的, 达到一种资源的公平分配, 先到达的任务 (元素) 先处理, 但有时需要在队列中基于优先级处理对象。 存入队列中的任务 (元素) 具有优先级, 需要根据优先级修复里面的数据。而在 JDK 1.5 引入…

如何使用WMS仓储管理系统实现流程优化

随着企业对于物流管理的需求日益增长&#xff0c;自动化WMS仓储管理系统已经成为了现代企业的核心工具之一。通过引入信息化技术&#xff0c;我们可以实现仓库管理流程的不断调整和优化&#xff0c;从而更好地满足客户的多样化需求。 一、信息化技术的引领 在现代仓库管理中&a…

声音响度、声压级计权(A B C)实现

声压 sound pressure 声压就是大气压受到声波扰动后产生的变化&#xff0c;即为大气压强的余压&#xff0c;它相当于在大气压强上的叠加一个声波扰动引起的压强变化。由于声压的测量比较容易实现&#xff0c;通过声压的测量也可以间接求得质点速度等其它物理量&#xff0c;所以…

探究Kafka原理-5.Kafka设计原理和生产者原理解析

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44…

快速开发表单好用吗?优势在哪?

如果应用快速开发表单&#xff0c;对提升企业的办公效率帮助巨大。在快节奏的现代社会生活中&#xff0c;职场办公也需要采用更专业的办公软件实现高效率提升。低代码技术平台就是如今常用于职场办公中的优质平台&#xff0c;其可视化操作、简单灵活、组件丰富等优势特点&#…

【cf 158 c】

给你一个整数数组 a1,a2,…,an ( )。在一次操作中&#xff0c;你可以选择一个整数 x ( )&#xff0c;并用 ⌊⌋ 替换 ai ( ⌊y⌋ 表示将 y 舍入为最接近的整数)。 来替换从 1 到 n 的所有 i。请注意&#xff0c;每次操作都会影响数组中的所有元素。打印使数组中所有元素相等所…

8.统一异常处理 + 统一记录日志

目录 1.统一异常处理 2.统一记录日志 1.统一异常处理 在 HomeController 类中添加请求方法&#xff08;服务器发生异常之后需要统一处理异常&#xff0c;记录日志&#xff0c;然后转到 500 页面&#xff0c;需要人工处理重定向到 500 页面&#xff0c;提前把 500 页面请求访问…

linux下的工具---yum

一、什么是yum yum是Linux下的软件包管理器 二、什么是软件包管理器 1、在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 2、但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在…

postman自动化接口测试

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

编程难点:常见问题及解决方案

目录 1 前言2 学习成本高2.1 学习成本高的问题2.2 学习成本高的解决方法 3 程序bug多3.1 程序bug多的问题 4 程序的性能调试4.1 程序的性能问题4.1 程序的性能调试方法 5 跨平台兼容性差5.1 跨平台兼容问题5.1 跨平台兼容问题的解决方法 6 解决技术难题的方法总结7 总结 1 前言…

leetcode9.回文数

回文数 0.题目1.WJQ的思路2.实现过程2.0 原始值怎么一个个取出来&#xff1f;2.1 取出来的数如何存到新的数字后面&#xff1f;2.2完整的反转得到新数的过程 3.完整的代码4.可运行的代码5.算法还可以优化的部分 0.题目 给你一个整数 x &#xff0c;如果 x 是一个回文整数&…

如何在本地安装部署WinSCP,并实现公网远程本地服务器

可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器 文章目录 可视化文件编辑与SSH传输神器WinSCP如何公网远程本地服务器1. 简介2. 软件下载安装&#xff1a;3. SSH链接服务器4. WinSCP使用公网TCP地址链接本地服务器5. WinSCP使用固定公网TCP地址访问服务器 1. 简介 …

C++ 红黑树插入详解

前言 在之前&#xff0c;我们学习了AVL树&#xff0c;知道了AVL树是一个平衡二叉搜索树&#xff0c;如果没学过AVL树&#xff0c;这篇文章看起来会很吃力&#xff0c;不清楚如何旋转的&#xff0c;建议可以先看AVL树的内容。 今天我们要学习的红黑树&#xff0c;他也是一颗平衡…

Vue3使用kkFileView预览文件pdf

kkFileView - 在线文件预览kkFileView官网 - kkFileView使用Spring Boot搭建&#xff0c;易上手和部署&#xff0c;基本支持主流办公文档的在线预览&#xff0c;如doc,docx,Excel,pdf,txt,zip,rar,图片等等https://kkfileview.keking.cn/zh-cn/docs/usage.html业务场景&#xf…

STM32 外部中断配置与中断函数设计

单片机学习 目录 文章目录 一、外部中断配置步骤 1.1配置RCC 1.2配置GPIO 1.3配置AFIO 1.4配置EXTI 1.5配置NVIC 二、中断函数设计 总结 一、外部中断配置步骤 第一步&#xff1a;配置RCC&#xff0c;把涉及外设的时钟打开。第二步&#xff1a;配置GPIO&#xff0c;选择…

【好书推荐-第30期】开发者请注意!因果推断与机器学习,终于有人能讲明白啦!

本文目录 一、因果推断二、因果推断的前世今生三、总结四、赠书条件 今天给各位读者推荐一本好书&#xff1a;《机器学习高级实践&#xff1a;计算广告、供需预测、智能营销、动态定价》&#xff0c;好书链接。 2023年初是人工智能爆发的里程碑式的重要阶段&#xff0c;以Open…

【JavaEE初阶】 博客系统项目--前端页面设计实现

文章目录 &#x1f332;主要内容&#x1f38d;预期效果&#x1f6a9;博客列表页效果&#x1f6a9;博客详情页&#x1f6a9;博客登录页&#x1f6a9;博客编辑页 &#x1f340;实现博客列表页&#x1f6a9;实现导航栏&#x1f388;页面主体部分 &#x1f384;实现博客详情页&…

Linux MeterSphere一站式开源持续测试平台远程访问

文章目录 前言1. 安装MeterSphere2. 本地访问MeterSphere3. 安装 cpolar内网穿透软件4. 配置MeterSphere公网访问地址5. 公网远程访问MeterSphere6. 固定MeterSphere公网地址 前言 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能&am…