Python Flask上下文管理机制详解:请求与应用上下文的生命周期
本文深入解析Python Flask框架中的上下文管理机制,详细区分请求上下文(Request Context)与应用上下文(Application Context)的定义、属性及生命周期。通过解析LocalStack栈结构、werkzeug的Local对象线程隔离原理,以及g对象的使用场景,阐明在视图内外如何正确推入和管理上下文,帮助开发者理解Flask底层基于WSGI的请求处理流程。
Flask上下文机制概述
前言
在语言学中,上下文指代语句所处的具体语境或语言环境。若孤立地看待一句含义模糊的话,往往难以理解其真实意图;而一旦结合具体的语言环境进行说明,语义便会清晰许多。这体现了语境对语意理解的显著影响。
在编程领域,上下文被定义为一种有序的属性序列,旨在为驻留在特定环境中的对象定义其运行背景。在对象被激活的过程中,系统会创建相应的上下文,并将对象配置为依赖某些自动服务,例如同步机制、事务处理、实时激活以及安全性控制等。
以计算机进程为例,上下文即进程执行时的运行环境,具体涵盖各类变量与数据,包括所有寄存器变量、进程打开的文件句柄以及内存信息等。可以将上下文理解为运行环境的一个快照,它是一个用于保存当前状态的对象。在程序开发中,大多数函数并非完全孤立存在,当函数执行自身逻辑时,往往需要与其他模块交互,并依赖外部环境变量。上下文的作用正是为这些外部变量赋值,确保函数能够正确运行。
请求上下文与应用上下文详解
请求上下文
关于WSGI
WSGI(全称Web Server Gateway Interface)是Python语言中定义的一种Web服务器与Web应用程序之间的简单且通用的接口标准。它封装了接收HTTP请求、解析HTTP请求、发送HTTP响应等底层代码与操作,使开发者能够更高效地编写Web应用。
Flask框架提供了两种核心上下文:一种是应用上下文(Application Context),另一种是请求上下文(Request Context)。
- RequestContext 请求上下文
- Request 对象封装了HTTP请求(environ)的具体内容。
- Session 根据请求中的Cookie,重新载入与该访问者相关的会话信息。
- AppContext 程序上下文
- g 用于在请求处理期间临时存储对象,每次新的请求都会重置该变量。
- current_app 当前激活程序的程序实例。
参见Flask上下文官方文档 请求上下文 和 应用上下文.
1. application 指的就是当你调用app = Flask(__name__)创建的这个对象app;
2.request 指的是每次http请求发生时,WSGI server(比如gunicorn)调Flask.call()之后,在Flask对象内部创建的Request对象;
3.application 表示用于响应WSGI请求的应用本身,request 表示每次http请求;
4.application的生命周期大于request,一个application存活期间,可能发生多次http请求,所以,也就会有多个request
上下文的生命周期管理
生命周期
- current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。
- Request和g的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了
- Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session。
底层原理:LocalStack与线程隔离
Flask处理流程

local线程隔离对象
不用local对象的情况
from threading import Thread
request = '123'
class MyThread(Thread):
def run(self):
global request
request = 'abc'
print('子线程',request) #子线程 abc
mythread = MyThread()
mythread.start()
mythread.join()
print('主线程',request) #主线程 abc
如果用local对象,在每个线程中都是隔离的
from threading import Thread
from werkzeug.local import Local
locals = Local()
locals.request = '123'
class MyThread(Thread):
def run(self):
locals.request = 'abc'
print('子线程',locals.request) #子线程 abc
mythread = MyThread()
mythread.start()
mythread.join()
print('主线程',locals.request) #主线程 123
app上下文和request上下文
应用上下文和请求上下文都是存放在一个‘LocalStack'的栈中,和应用app相关的操作就必须要用到应用上下文,比如通过current_app获取当前的这个app的名字。和请求相关的操作就必须用到请求上下文,比如使用url_for反转视图函数。
在视图函数中,不用担心上下文的问题,因为视图函数要执行,name肯定是通过访问url的方式执行的,name这种情况下,Flask底层就已经自动的帮我们把请求上年文和应用上下文都推入到了相应的栈中。如果想要在视图函数外面执行相关的操作,name就必须要手动推入相关的上下文手动推入请求上下文:推入请求上下文到栈中,会首先判断有没有应用上下文,如果没有那么就会先推入应用上下文到栈中,然后再推入请求上下文到栈中。
app上下文
from flask import Flask,current_app
app = Flask(__name__)
#如果在视图函数外部访问,则必须手动推入一个app上下文到app上下文栈中
#第一种方法
# app_context = app.app_context()
# app_context.push()
# print(current_app.name)
#第二种方法
with app.app_context():
print(current_app.name) #context_demo
@app.route('/')
def index():
# 在视图函数内部可以直接访问current_app.name
print(current_app.name) #context_demo
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
request请求上下文
from flask import Flask,current_app,url_for
app = Flask(__name__)
#应用上下文
#如果在视图函数外部访问,则必须手动推入一个app上下文到app上下文栈中
with app.app_context():
print(current_app.name) #context_demo
@app.route('/')
def index():
# 在视图函数内部可以直接访问current_app.name
print(current_app.name) #context_demo
return 'Hello World!'
@app.route('/list/')
def my_list():
return 'my_list'
# 请求上下文
with app.test_request_context():
# 手动推入一个请求上下文到请求上下文栈中
# 如果当前应用上下文栈中没有应用上下文
# 那么会首先推入一个应用上下文到栈中
print(url_for('my_list'))
if __name__ == '__main__':
app.run(debug=True)
上下文栈结构设计原理
为什么上下文需要放在栈中?
1.应用上下文:
Flask底层是基于werkzeug,werkzeug是可以包含多个app的,所以这时候用一个栈来保存,如果你在使用app1,那么app1应该是要在栈的顶部,如果用完了app1那么app应该从栈中删除,方便其他代码使用下面的app。
2.应用上下文:
如果在写测试代码,或者离线脚本的时候,我们有时候可能需要创建多个请求上下文,这时候就需要存放到一个栈中了。使用哪个请求上下文的时候,就把对应的请求上下文放到栈的顶部,用完了就要把这个请求上下文从栈中移除掉。
g对象的线程隔离使用
线程隔离的g对象
g对象是在整个Flask应用运行期间都是可以使用的,并且它也是跟request一样是线程隔离的。这个对象是专门用来存储开发者自定义的一些数据,方便在整个Flask程序中都可以使用。一般使用就是,将一些经常会用到的数据绑定到上面,以后就直接从g上面取就可以了,而不是通过传参的形式,这样更加方便。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













