#Flask 上下文深挖:current_app、g、request、session 的底层逻辑
📂 所属阶段:第五阶段 — 高级进阶(性能与架构)
🔗 相关章节:路由(Routing)艺术 · 环境搭建
#1. Flask 四大上下文
┌──────────────────────────────────────┐
│ 应用上下文 (App Context) │
│ ┌──────────────┐ ┌───────────────┐ │
│ │ current_app │ │ g │ │
│ │ (当前应用) │ │ (请求级全局) │ │
│ └──────────────┘ └───────────────┘ │
├──────────────────────────────────────┤
│ 请求上下文 (Request Context) │
│ ┌──────────────┐ ┌───────────────┐ │
│ │ request │ │ session │ │
│ │ (当前请求) │ │ (会话数据) │ │
│ └──────────────┘ └───────────────┘ │
└──────────────────────────────────────┘#2. current_app(当前应用实例)
# current_app = 当前 Flask 应用实例
# 用于:在应用工厂、扩展、工具函数中访问应用配置
# ❌ 错误:无法在模块级别访问
app = create_app() # 还没创建就访问?
print(app.config["SECRET_KEY"])
# ✅ 正确:在应用上下文中访问
def create_app():
app = Flask(__name__)
@app.route("/")
def index():
return current_app.config["APP_NAME"]
return app
# 在扩展中使用
class MyExtension:
def init_app(self, app):
self.secret = app.config["SECRET_KEY"]#3. g(请求级全局对象)
# g = 每个请求独立的全局对象,请求结束后自动清除
# 用于:在同一个请求的多个函数间共享数据
from flask import g
@app.before_request
def load_user():
"""每个请求前加载用户(只查一次)"""
g.user_id = session.get("user_id")
g.user = User.query.get(g.user_id) if g.user_id else None
@app.route("/profile")
def profile():
# 多个函数都能访问 g.user,不需要重复查询
if g.user:
return f"欢迎,{g.user.name}"
return "未登录"
@app.route("/dashboard")
def dashboard():
# 同样可以访问
if g.user:
return f"{g.user.name} 的仪表盘"
return "请登录"#4. request(当前请求)
from flask import request
@app.route("/submit", methods=["POST"])
def submit():
# 表单数据(application/x-www-form-urlencoded)
username = request.form.get("username")
password = request.form.get("password")
# JSON 数据(application/json)
data = request.get_json()
name = data.get("name")
# URL 参数(?key=value)
page = request.args.get("page", 1, type=int)
# 请求头
user_agent = request.headers.get("User-Agent")
auth = request.headers.get("Authorization")
# 请求方法
if request.method == "POST":
...
# 上传的文件
file = request.files.get("avatar")
if file:
file.save("/path/to/save")
# 请求 URL
print(request.url) # 完整 URL
print(request.endpoint) # 视图函数名(如 "articles.detail")
print(request.blueprint) # 当前蓝图名
return "OK"#5. session(会话数据)
from flask import session
# 设置会话数据
session["user_id"] = user.id
session["username"] = user.username
session.permanent = True # 设置长期有效(需配置 PERMANENT_SESSION_LIFETIME)
# 读取会话数据
user_id = session.get("user_id")
# 删除会话数据
session.pop("user_id", None)
# 清空整个会话
session.clear()
# 加密签名 Cookie 存储(浏览器端,不可篡改)
# 存储格式:Cookie: session=eyJ1c2VyX2lkIjoyfQ==...(签名)#6. 上下文的工作原理
# 上下文 = 请求线程/协程 + 本地存储(Local)
# Flask 使用 werkzeug.local.Local 实现线程/协程安全
# 每个请求在独立的 "命名空间" 中操作
# 示例:werkzeug.local.Local 的工作方式
from werkzeug.local import LocalStack, Local
local = Local()
local.request_id = 1 # 线程 A
# 线程 B 访问 local.request_id → AttributeError(隔离!)
# Flask 自动为每个请求:
# 1. 创建 App Context
# 2. 创建 Request Context(包含 session、g)
# 3. 请求结束后清理#7. 小结
# 四大上下文速查
current_app # 当前 Flask 应用实例(App Context)
g # 请求级全局对象,请求结束自动清除(App Context)
request # 当前 HTTP 请求(Request Context)
session # 加密 Cookie 存储的会话数据(Request Context)
# 使用场景
with app.app_context():
# 在应用外创建上下文
with app.test_request_context():
# 在测试中创建请求上下文
print(current_app.name)💡 理解上下文:上下文让 Flask 的函数和类可以在任意位置访问当前应用、请求和会话数据,无需显式传递参数。
🔗 扩展阅读

