首页 > 其他分享 >Flask之钩子函数

Flask之钩子函数

时间:2023-06-04 21:34:44浏览次数:60  
标签:__ 函数 Flask 钩子 app request print def before

Flask之钩子函数

类似django的中间件,作用就是在进入框架的之后 http方法之前或返回response之前进行一些操作 Flask的钩子函数可在注册时根据注册的app或者蓝图从而确定钩子函数作用的范围(可全局 也可作用某一个蓝图)

钩子函数

钩子函数可以分为两层说明,第一层是 app 层,第二层则是 blueprint 层

app 层

app 层的钩子函数有 before_request,before_first_request,after_request,teardown_request,下面我们一一分析。

after_request 和 teardown_request 的区别

两者最大的区别是在于,从Flask 0.7开始,如果出现未处理的异常,after_request 将不会被执行,而后者将正常运行并接收异常,其次还有两者的执行顺序,让我们通过代码去了解一下.

from flask import Flask, g, request

app = Flask(__name__)

@app.before_request
def before_request():
    print('before request started, %s' % request.url)

@app.before_first_request
def before_request():
    print('before first request started, %s' % request.url)

@app.after_request
def after_request(reponse):
    print("after request started, %s" % request.url)
    return reponse

@app.teardown_request
def teardown_request(exception):
    print("teardown request,%s,%s" % (exception,request.url))

@app.route('/')
def index():
    return 'Hello'

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

结果如下:

结果很清晰,after_request 先执行(注意这个图和代码)

blueprint 层

blueprint 层关于request 的钩子函数其实和app层基本一致,有两点区别:

  1. 与 app 层相比,blueprint 层少了一个 before_first_request 的钩子函数
  2. 多了一些,可以在蓝图调用 app 层的钩子函数:before_app_first_request,before_app_request,after_app_request,after_app_request,teardown_app_request

请求上下文(request context)

为什么这里会突然出现这个标题呢?我们在哪里用到了这个吗?还记得上个图吗,我们在所有的请求中都访问了request对象,并且成功了输出了 url,

但是我们并没有传入它,它是一个全局对象吗?让我们测试一下:

from flask import Flask, g, request

app = Flask(__name__)

def test_request():
    print("test request,%s" % request.url)

test_request()

@app.route('/')
def index():
    return 'Hello'

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

看一下截图:

由此可见 request 对象仅可以在请求上下文的生命周期可以访问,由此不难得出,我们上面说到几个钩子函数也是挂载到请求上下文的生命周期的不同阶段从而发挥作用的。

方法:

一共四种方方法

before_first_request()

执行时间:在处理第一个请求前运行 before_request之前

格式:

@App.before_first_request
def before_app_first_request():
    print('只有在处理第一次请求之前执行')

参数:

​ 没有参数

返回值:

​ None 请求继续

​ response对象 终止本次请求 直接返回结果

示例:

注意:和 before_request 不同的是, 它的非空返回值会被忽略。

问题来了:before_first_request 和 before_request 加载顺序是什么样子呢?

让我们通过下面的代码看一下:

from flask import Flask, g, request

app = Flask(__name__)

@app.before_request
def before_request():
    print('before request started')

@app.before_first_request
def before_request():
    print('before first request started')

@app.route('/')
def index():
    return 'Hello'

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

结果如图:这次 first_request 胜出了。

 

before_request()

执行时间:每次请求都执行 http方法之前

格式:

@App.before_request
def before_app_request():
    print('在视图函数执行之前执行')

参数:

​ 没有参数

返回值:

​ None 请求继续

​ response对象 终止本次请求 直接返回结果

示例:

from flask import Flask,

app = Flask(__name__)

@app.before_request
def before_request():
    print('before request started')
    return "example01" 

@app.route('/')
def index():
    return 'Hello world'' 

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

这个例子下当访问 localhost:5000/的时候,前端渲染的值为 “example01” 而不是 “Hello world”

 

after_request()

执行时间:如果没有未处理的异常抛出,在每次请求后运行(http方法之后执行)

格式:

@App.after_request
def after_request(response):
    pass
    return response

参数:

​ 视图方法中返回的response对象

返回值:

​ response对象 可在返回前修改

 

teardown_request()

执行时间:在每次请求后运行,即使有未处理的异常抛出也执行

格式:

# 请每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
@app.teardown_request
def teardown_request(e):
    print("teardown_request")

参数:

​ exception错误信息

返回值:

​ None

示例:仿照Django中的中间件

第一步

应用目录下创建middlewares包目录,每个功能实现以个中间件(每个功能是一个py文件)

第二步

在middlewares目录下创建中间件文件

from flask import request
from flask import session
from flask import g

#参数:蓝图对象
def verifycodeMiddleware(blueprint):
    @blueprint.before_request
    def before():
        print("------验证验证码-------")

第三步

注册中间件(蓝图文件中)

# 注册中间件
from myApp.middlewares import verifycodeMiddleware
verifycodeMiddleware(myApp)

扩展:

from flask import request
from flask import session
from flask import g

#参数:蓝图对象
def verifycodeMiddleware(app):
    @app.before_request
    def before():
        print("****验证验证码****")
app.py -》注册 verifycodeMiddleware(app)

说明

# 钩子函数
@myApp.before_first_request
def first():
    print("-------------first")
@myApp.before_request
def before():
    print("-------------before")
    # 验证验证
    # 获取前端发送的验证码
    # 获取session中的验证码
    # 判断两者是否相同,相同返回None,否则重定向会登陆界面

    # 验证是否登录
    # 获取状态保持相关信息(账号)
    # 如果没有状态保持说明没有登陆,重定向登陆界面
    # 根据状态保持的账号获取用户对象
    # 获取客户端发送的cookie中的键为token的值
    # 如果没有说明没有登陆,重定向登陆界面
    # 判断用户中的token与cookie中的token值是否相同,不相同则重定向登陆界面
@myApp.after_request
def after(response):
    print("-------------after")
    return response

@myApp.teardown_request
def teardown(exception):
    print("-------------teardown")
    print(exception)

什么是g

from flask import g

flask,g对象是专门用来存储用户数据的,它是global的缩写,g是全局变量,在整个request生命周期内生效。

g对象如何使用

1.官方解释

The application context is created and destroyed as necessary. It never moves between threads and it will not be shared between requests.
As such it is the perfect place to store database connection information and other things. The internal stack object is called flask.appctx_stack.
Extensions are free to store additional information on the topmost level, assuming they pick a sufficiently unique name and
should put their information there, instead of on the flask.g object which is reserved for user code.

2.非官方解释
g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别,像数据库配置这样重要的信息挂载在app对象上,一些用户相关的数据,就可以挂载在g对象上,这样就不需要在函数里一层层传递。

3.使用案例

 

from flask import Flask, request, g


app = Flask(__name__)


@app.route('/youhui')
def youhui():
    grade = request.args['grade']
    g.grade = grade
    return get_amount_by_grade()


def get_amount_by_grade():
    grade = g.grade
    if grade == 'a':
        return '100'
    else:
        return '80'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5500)

g对象的出现,让你在任何位置都能获得用户数据,避免了在函数参数里传递这些数据。

g对象的生命周期

g对象在整个request请求处理期间生效,这表明,g对象是与request是一一对应的。一次request请求,就有一个g对象,在这次请求之前,之后,以及同时间的请求里,他们互不干扰。

你在g对象里存储的数据,只能在这一次请求里使用,请求处理结束后,这个g对象就销毁了,存储的数据也就不见了。

g对象的生命周期虽然只是一次请求的生命周期,但它是一个应用 上下文对象

g对象和session的区别(非官方)

session对象是可以跨request的,只要session还未失效,不同的request的请求会获取到同一个session,但是g对象不是,g对象不需要管过期时间,请求一次就g对象就改变了一次,或者重新赋值了一次。

也就是说session可以在我们的这个网站随意都可以用 而 g只能是这次的请求如果重定向之后就会改变。

感谢分享:

https://blog.csdn.net/weixin_44795429/article/details/115279400
https://blog.csdn.net/General_zy/article/details/122265428

标签:__,函数,Flask,钩子,app,request,print,def,before
From: https://www.cnblogs.com/hhaostudy/p/17456180.html

相关文章

  • C++ 多态 虚函数virtual
    先解释虚函数,对于基类,子类继承基类后可能会调用其某个函数FA,而不同的子类继承了同一个基类后需要基类内某个同样的函数FA但又不是同个作用,此时则会在对应的子类内对应重载派生出FA_B函数和FA_C函数,而这时要求FA为虚函数(virtual)那为什么不各自写成一个函数B和C呢?这就是多态的意......
  • Linux下三组I/O复用函数的比较(select、poll、epoll)
        前面我们讨论了select、poll和epoll三组I/O复用系统调用,这三组系统调用都能同时监听多个文件描述符。它们将等待由timeout参数指定的超时时间,直到一个或多个文件描述符上有事件发生时返回,返回值是就绪的文件描述符的数量。返回0表示没有事件发生。现在我们从事件集、最......
  • Excel批量插入图片(Excel函数集团)
    批量插入图片,归函数集团管了?对,你没看错,就是函数集团的活!因为Microsoft365出了一个新函数:IMAGE!所以,以前折腾的那种一堆合并以后再贴进txt文本文件再贴回来的,没用了?是与不是,我们用实例来说话! ***一条不算太华丽的分割线***准备工作1:一堆图片图片还是那个图片,但保存的位置却不是那个......
  • c++函数调用压栈过程
    c++函数调用,栈内情况如下图所示:首先主函数将被调函数所需参数从右至左压入栈中然后再将主函数地址即返回地址EIP压入栈中再将主函数栈基址EBP压入栈中,此时构造被调函数栈,将当前ESP值mov给EBP,即被调函数栈从此处开始上图ida反汇编代码,可以看到对变量的使用,参数(argc,argv,env......
  • property 用于以访问属性的方式调用函数
    property是Python内置的功能,常用来修饰类方法,用于以访问属性的方式调用函数。描述符对象为了能够实现访问属性就调用某个函数,这里将利用描述符对象作为本文的实现起点,当某个类定义了__get__方法后,通过其方法名称可以直接调用__get__proptery主要依赖于描述符的机制。p......
  • 定义全局函数、变量
    定义全局函数、变量定义全局函数声明定义在一个头文件inline如一些很短的工具函数,创建目录,删除目录之类的#include<string>#include<filesystem>namespacewwc{ voidinlineCreateDir(std::stringpath){ std::stringcmd="mkdir-p"+path; std::system(cmd......
  • 【python】函数print
    f-string python中的字符串通常被括在双引号("")或单引号('')内。要创建f-string,你只需要在字符串的开头引号前添加一个 f 或 F。例如,"This" 是一个字符串,而 f"This" 是一个f-string。当使用f-string来显示变量时,你只需要在一组大括号 {} 内指定变量的名字。而在运行时......
  • 防抖函数
    习题链接防抖函数课程列表当一个函数在一定时间内被连续调用多次时,只执行最后一次调用,并在最后一次调用后延迟一定时间再执行。关键点setTime()定时器创建一个变量来存储定时器每次执行函数的时候,都要先清除上一次的定时器,以达到只执行最后一次调用闭包的概念,因为每一......
  • flatten()是对多维数据的降维函数
    flatten()是对多维数据的降维函数。flatten(),默认缺省参数为0,也就是说flatten()和flatte(0)效果一样。fromnumpyimport*a=array([[1,2],[3,4],[5,6]])aarray([[1,2],[3,4],[5,6]])a.flatten()array([1,2,3,4,5,6])......
  • Jmeter函数助手41-unescapeHtml
    unescapeHtml函数用于将HTML转义过的字符串反转义为Unicode字符串。Stringtounescape:填入字符 1、escapeHtml函数是将字符进行HTML转义,unescapeHtml函数函数则是将HTML转义过的字符反转,unescapeHtml函数和escapeHtml函数功能刚好相反。${__unescapeHtml(value="hello"+"w......