Python 现代开发学习笔记

(五)请求上下文、应用上下文与资源收尾

1. 当前请求与当前应用分别保存信息

路由中能写 request.args,是因为 Flask 在处理请求时建立了请求上下文;应用配置和资源则通过应用上下文取得。先观察能在不同位置读取什么。

# 项目文件:demos/context_trace.py
# 分别进入应用上下文和请求上下文,观察代理对象在上下文退出后的可用状态。
from flask import Flask, current_app, g, request

app = Flask(__name__)
try:
    print(request.path)
except RuntimeError:
    print("请求之外,没有 request.path")

with app.app_context():
    g.label = "本次命令的资源"
    print("应用上下文", current_app.name, g.label)
    try:
        print(request.path)
    except RuntimeError:
        print("只有应用上下文,仍然没有 HTTP 请求")

with app.test_request_context("/books?finished=0"):
    print("请求上下文", request.path, request.args["finished"])
    print("新上下文是否沿用 label", hasattr(g, "label"))

应用上下文让 current_app 和 g 可用,单独创建它不会凭空产生一条 HTTP 请求。test_request_context 则准备请求数据,也同时准备所需的应用上下文。这个方法只准备上下文,不会自动执行路由和 before_request;需要经过完整分发时,用测试客户端发送请求。

g 是应用上下文中的临时存放处。通常一条请求会有自己的应用上下文,因此数据库连接放在 g.db 后可以在本次请求内复用,结束时清理。命令行也可以用 with app.app_context() 建立一次应用上下文,使用相同数据库函数。

前一章的 SQLAlchemy Session 是 ORM 工作对象;Flask 的 session 是当前浏览器会话的数据映射;g 又是这次应用上下文的临时数据。它们解决的问题不同,不能仅凭名字都像“会话”就混在一起。

请求开始同时建立请求和应用上下文,request 保存 HTTP 数据,current_app 指向配置,g 保存当前工作资源,结束后逐层清理

可以对照 请求上下文 与 应用上下文 查阅对象的生命周期。

2. 沿一次请求观察回调顺序

# 项目文件:demos/lifecycle_trace.py
from flask import Flask

app = Flask(__name__)
events = []


@app.before_request
def prepare():
    events.append("before:准备")


@app.get("/")
def index():
    events.append("view:处理")
    return "书架"


@app.after_request
def decorate(response):
    events.append("after:补响应头")
    response.headers["X-Example"] = "flask"
    return response  # after_request 必须交回响应对象。


@app.teardown_request
def finish_request(_error):
    events.append("teardown:请求收尾")


@app.teardown_appcontext
def finish_app(_error):
    events.append("teardown:应用上下文收尾")


client = app.test_client()
print(client.get("/").headers["X-Example"])
print(events)

事件依次为准备、视图处理、补响应头、请求收尾、应用上下文收尾。before_request 可以准备用户身份;返回响应时也可以提前结束这次分发。after_request 接收响应并交回响应,适合补头。teardown_appcontext 适合关闭保存在 g 中的连接,正常和异常路径都会执行。

数据库提交放在业务动作成功的位置,连接关闭放在收尾位置。被处理过的 HTTP 错误与异常对象之间的关系并不等于事务是否成功,因此本章不会靠收尾参数决定是否提交。

before 准备身份后进入视图,视图形成响应,after 修改响应,再进行请求与应用上下文收尾;业务事务在形成成功结果之前完成

笔记正文与全部题解 · Ctrl / ⌘ K