← 返回题目列表

Flask 的应用上下文和请求上下文有什么区别?

高频 中等 第 2 / 27 题 更新于 2026/07/27
Flask应用上下文请求上下文LocalProxy

简化版

Flask 有应用上下文和请求上下文。应用上下文保存当前应用相关信息,让 current_appg 可用;请求上下文保存当前请求相关信息,让 requestsession 可用。请求上下文通常会自动伴随应用上下文一起推入,请求结束后再弹出。

详细版

Flask 中常见上下文对象:

  • current_app:当前 Flask 应用对象,属于应用上下文。
  • g:一次应用上下文中的临时全局对象,常用于保存数据库连接、当前用户等临时数据。
  • request:当前请求对象,属于请求上下文。
  • session:当前请求的会话对象,属于请求上下文。

它们都不是普通全局变量,而是上下文局部代理。Flask 根据当前执行环境找到对应的上下文数据。

如果在没有请求或应用上下文的地方访问这些对象,会出现类似 “working outside of application context” 或 “working outside of request context” 的错误。解决方式不是随便导入 app,而是在命令行、脚本、测试、后台任务中显式推入上下文。

完整版教学

一、为什么 Flask 需要上下文

Web 服务是并发处理请求的。多个用户可能同时访问同一个接口,但视图里却可以直接写:

from flask import request

user_agent = request.headers.get("User-Agent")

如果 request 真的是普通全局变量,就会产生严重并发问题:用户 A 的请求数据可能被用户 B 覆盖。Flask 的做法是使用上下文局部对象,也就是你看到的是一个代理对象,真正的数据按当前请求隔离保存。

这套机制让代码写起来像访问全局变量,但实际语义是“访问当前请求或当前应用对应的数据”。这就是 Flask 上下文的核心价值。

二、请求上下文保存什么

请求上下文和一次 HTTP 请求强相关,主要让这些对象可用:

from flask import request, session

request 保存请求方法、路径、参数、Header、Body、文件等信息;session 保存当前用户会话数据。它们只有在请求处理期间才有意义。请求结束后,上下文弹出,再访问它们就会报错。

例如下面代码在视图外直接执行会出问题:

print(request.path)

因为此时没有当前请求。面试时要强调:request 是当前请求上下文里的对象,不是随时可用的全局状态。

三、应用上下文保存什么

应用上下文和 Flask 应用相关,主要让这些对象可用:

from flask import current_app, g

current_app 指向当前应用对象,常用于读取配置、日志等:

current_app.config["DATABASE_URL"]

g 是一个临时存储对象,常用于一次请求或一次上下文期间共享数据:

from flask import g

def get_db():
    if "db" not in g:
        g.db = connect_db()
    return g.db

g 不是跨请求缓存。请求结束后,相关上下文会清理,g 中的数据也不应该被当成持久状态。

四、应用上下文和请求上下文的关系

一次正常 HTTP 请求进来时,Flask 通常会同时推入请求上下文和应用上下文。请求上下文依赖应用上下文,因为处理请求必须知道当前属于哪个 app。

但应用上下文可以单独存在。比如在命令行脚本、测试、初始化任务中,你可能不处理 HTTP 请求,但需要读取 current_app.config 或初始化扩展,这时可以手动推入应用上下文:

with app.app_context():
    init_database()

如果你在脚本里访问 current_app 报 “working outside of application context”,通常就是缺少 app.app_context()

五、LocalProxy 和上下文局部的理解

Flask 的 requestcurrent_app 等对象本质上是代理。代理对象会在访问属性时,到当前上下文中找到真实对象。这也是为什么你导入的是同一个 request 名字,但不同请求里读到的是不同数据。

早期 Flask 主要依赖线程/协程局部存储实现隔离,现代版本底层更多基于 Python 的 contextvars。面试不一定要讲到底层源码,但至少要说清楚:这些对象不是全局共享状态,而是按上下文隔离。

六、常见错误和工程场景

常见错误一:在后台线程或 Celery 任务里直接使用 request。后台任务已经脱离 HTTP 请求上下文,应该把需要的数据作为参数传进去,而不是依赖 request

常见错误二:把 g 当成全局缓存。g 的生命周期跟上下文有关,不适合保存跨请求数据。跨请求缓存应该使用 Redis、内存缓存或数据库。

常见错误三:测试中忘记创建上下文。测试视图时可以用 app.test_client(),测试依赖 current_app 的函数时可以用 app.app_context()

七、常见误区与追问

对象所属上下文生命周期
request请求上下文单次 HTTP 请求
session请求上下文依赖当前请求的 Cookie 会话
current_app应用上下文当前 Flask app
g应用上下文一次应用上下文内的临时数据
  • 误区:requestcurrent_app 是普通全局对象。 它们是 LocalProxy 代理,访问时会到当前上下文中取真实对象。
  • 误区:g 可以当跨请求缓存。 g 只适合一次请求或一次应用上下文内临时存放数据,跨请求缓存应使用 Redis、数据库或进程内缓存。
  • 误区:后台任务里可以直接用 request。 后台任务脱离请求上下文,应把用户 ID、参数等必要数据显式传入。
  • 追问:请求上下文和应用上下文谁依赖谁? 请求处理通常需要知道当前 app,所以请求上下文会伴随应用上下文;应用上下文也可以单独推入。
  • 追问:为什么脚本里访问 current_app 会报错? 脚本没有自动请求入口,需要用 with app.app_context(): 手动推入应用上下文。
  • 追问:现代 Flask 为什么更适合异步和协程场景? 现代实现更多依赖 contextvars 隔离上下文,比单纯线程局部更适合协程并发模型。

记忆钩子:上下文让“看似全局”的对象按当前请求或当前应用隔离;报 outside context,先想有没有正确入栈。

八、加强记忆

Flask 上下文解决的是“看起来像全局变量,实际按当前请求或当前应用隔离”的问题。请求上下文让 request/session 可用,应用上下文让 current_app/g 可用;离开上下文访问这些对象会报错,后台任务和脚本要显式传参或手动推入上下文。