Flask 中的上下文管理和请求钩子

在使用 Flask 框架实现功能接口的时候,前端点击按钮发送请求的请求方式和 form 表单提交给后端的数据,后端都是通过 Flask 中的 request 对象来获取的。

在 Flask 框架中,这种传递数据的方式被称为上下文管理,在 Flask 框架中有四个上下文管理对象: request ,session , current_app 和 g 变量。

其中,request 和 session 被称为请求上下文,current_app 和 g 变量被称为应用上下文。

一、请求上下文 (request context)

Flask 中的上下文对象相当于一个容器,保存了 Flask 程序运行过程中的一些信息,如请求方式和表单数据。

请求上下文依赖于用户发送请求,它的使用范围是在后端的视图函数中,因为前端发送请求后,后端的路由会去找到对应的视图函数,所以只能在视图函数中使用。

1. request

在 Flask 中,request 对象封装了 HTTP 请求的内容,针对的是 HTTP 请求,保存了当前请求的相关数据。

可以直接在视图函数中使用 request 对象获取到当前请求的相关数据。如获取请求方式使用 request.method ,获取 form 表单提交的数据使用 request.form.get('name') ,name 是前端 form 表单的 name 属性,获取 url 中查询字符串的值使用 request.args.get('key'),获取的是 GET 请求的参数,key 是查询字符串的 key 值。

2. session

session 和 cookie 都是用来做状态保持的,cookie 依赖于浏览器,但 session 不需要,是请求会话的意思。

状态保持指的是用户登录的状态,所以依赖于用户的登录状态。

在请求会话中,可以保存和获取用户相关的信息。如使用 session['id'] = user.id 记录用户的 id 信息,然后通过 session.get('id') 获取用户的 id 信息。

二、应用上下文 (application context)

应用上下文不是一直存在的,它的作用是帮助请求对象获取当前 Flask 应用 app 的信息,发送请求之后才会有应用上下文,请求结束后应用上下文就会失效。

1. current_app

current_app 是应用程序上下文,用于存储 Flask 应用程序 app 中的变量,可以在 current_app 中存储一些变量。

通过 current_app ,可以将存储的变量获取出来(默认存储了很多信息),如可以通过 current_app.name 打印当前 app 的名称,可以获取应用的启动文件,启动时指定了哪些参数,加载了哪些配置文件,连了哪个数据库,有哪些工具类、常量,应用跑在哪个服务器上,IP多少,内存多大等。

2. g 变量

g 变量是当前请求中的一个临时全局变量,充当中间媒介的作用,可以使用它来保存数据和传递数据,g 变量保存的是当前请求的数据,在同一次请求后面的处理步骤中,可以取出保存的数据。

不同的请求中,g 变量是不同的,g 变量不能跨请求传递数据,在 Flask 底层实现中,不同请求的 g 变量通过 thread id 来区别。

接下来就演示上下文的使用方式,在项目文件夹下创建一个 flask_context.py 文件,然后添加如下代码。

from flask import Flask, request, session, current_app, g

app = Flask(__name__)

app.config['SECRET_KEY'] = 'sfasfjlksfjwerhuiuygjn'
app.config['DEBUG'] = True


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

method = request.method
print(method)
arg = request.args.get('arg')
print(arg)
session['id'] = 1
id = session.get('id')
print(id)
secret_key = current_app.config.get('SECRET_KEY')
print(secret_key)
g.name = 'JackMa'
print(g.name)

return 'Hello Context!'


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

写好代码后,运行 flask_context.py ,在浏览器中访问 ​​http://127.0.0.1:5000/?arg=flask​​ ,后端控制台的打印结果如下:

GET
flask
1
sfasfjlksfjwerhuiuygjn
JackMa

三、 Flask 中的请求钩子

在 Flask 项目中,前端和后端进行数据交互,会有一些准备工作或扫尾工作需要处理,如在请求开始时,建立数据库连接,进行用户权限校验,在请求结束时,处理数据的格式等。

如果每个接口都需要进行准备工作和扫尾工作,那这些接口的视图函数中就会写相同的代码,一个接口写一遍,重复很多。

为了避免在视图函数中编写重复功能的代码,Flask 提供了通用的功能,请求钩子。

请求钩子是指在请求刚开始时或请求即将结束时做的一些通用处理。

在 Python 中,可以使用装饰器的方式来实现,事实上,请求钩子就是通过装饰器实现的,开发人员直接调用即可。

Flask 提供了四种请求钩子装饰器:

1. before_first_request

在处理第一个请求前执行,如验证第一次访问网站时用户是否登录。

2. before_request

在每次请求前执行,如验证用户的状态保持是否过期。

3. after_request

如果没有抛出错误,在每次请求后执行。

接收一个参数:视图函数的响应对象 response 。

在此函数中可以对响应数据在返回之前做最后一步修改处理。

4. teardown_request:

在每次请求后执行。

接受一个参数:错误信息 e ,如果有相关错误则抛出。

接下来就演示一下请求钩子的使用效果,在项目文件夹下创建一个 flask_hook.py 文件,然后添加如下代码。

from flask import Flask

app = Flask(__name__)


@app.before_first_request
def before_first_request():
print("在处理第一个请求前执行")


@app.before_request
def before_request():
print("在每次请求前执行")


@app.after_request
def after_request(response):
print("如果没有抛出错误,在每次请求后执行")
response.headers["Content-Type"] = "application/json"
return response


@app.teardown_request
def teardown_request(e):
print('异常: ', e)
print("在每次请求后执行")


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


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

写好代码后,运行 flask_hook.py ,在浏览器中访问 ​​http://127.0.0.1:5000/​​ ,后端控制台的打印结果如下:

在处理第一个请求前执行
在每次请求前执行
如果没有抛出错误,在每次请求后执行
异常: None
在每次请求后执行

刷新一下浏览器页面,发送第二次请求,后端控制台的打印结果如下:

在每次请求前执行
如果没有抛出错误,在每次请求后执行
异常: None
在每次请求后执行

可以看到,第一次请求时,四个钩子函数都执行了,第二次请求时,before_first_request 没有执行,因为它只在第一次请求时执行,而两次请求中,访问的接口 / 对应的视图函数 index() 中都没有异常,所以 after_request 都会执行。

 

Flask 中的上下文管理和请求钩子_Flask 中的上下文管理