bigywater.tech
Flask · 8

before_request、after_request、teardown_request

三类钩子什么时候触发、触发几次、顺序如何、出了异常还跑不跑?这篇把各种请求都跑一遍,用事件顺序说话。

7
本篇对比的请求类型数
0 → 2
before_request 返回响应时被跳过的视图执行次数 vs 钩子之外(after、teardown)仍执行的钩子数
after 倒序
after_request 与 teardown_request 按注册的相反顺序执行

各种请求下的触发顺序

实测 · 本机执行输出
  钩子定义(简写):
      1 | @app.before_request   def b1 / b2         # b2 在 /short 返回响应,在 /before-boom 抛异常
      2 | @app.after_request    def a1 / a2         # 参数是响应,必须返回响应
      3 | @app.teardown_request def t1 / t2         # 参数是异常或 None
  正常 GET /           → 200  before_1 → before_2 → view → after_2 → after_1 → teardown_2(None) → teardown_1(None)
  abort(403)         → 403  before_1 → before_2 → view → after_2 → after_1 → teardown_2(None) → teardown_1(None)
  视图里 ValueError     → 500  before_1 → before_2 → view → after_2 → after_1 → teardown_2(ValueError) → teardown_1(ValueError)
  before 里直接返回响应     → 200  before_1 → before_2 → after_2 → after_1 → teardown_2(None) → teardown_1(None)
  before 里抛异常        → 500  before_1 → before_2 → after_2 → after_1 → teardown_2(RuntimeError) → teardown_1(RuntimeError)
  路径不存在(404)         → 404  before_1 → before_2 → after_2 → after_1 → teardown_2(None) → teardown_1(None)
  静态文件 /static/x     → 404  before_1 → before_2 → after_2 → after_1 → teardown_2(None) → teardown_1(None)

上一篇:请求进入 Flask 后的完整生命周期;下一篇:before_first_request 的变化与替代方案。

after_request 返回 None

实测 · 本机执行输出
  最后执行的 after_request 返回 None → test_client 抛出 TypeError: 'NoneType' object is not callable
  (after_request_funcs 按注册顺序存放,执行时倒序,所以 insert(0) 的函数最后执行(这里让它返回 None))

多个钩子的顺序

实测 · 本机执行输出
  before_0 → before_1 → before_2 → after_2 → after_1 → after_0 → teardown_2 → teardown_1 → teardown_0

蓝图里的钩子

实测 · 本机执行输出
  GET /in-bp   → 200  app.before_request → bp.before_app_request → bp.before_request → view(bp) → bp.after_request → app.after_request
  GET /in-app  → 200  app.before_request → bp.before_app_request → view(app) → app.after_request
  GET /nope    → 404  app.before_request → bp.before_app_request → app.after_request

TESTING 下的异常

实测 · 本机执行输出
  test_client 向上抛出了: ValueError boom
  before_1 → before_2 → view → teardown_2(ValueError) → teardown_1(ValueError)

分步演示

钩子顺序
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。404 与 500 的错误页本身由错误处理器生成,见第 10 篇
    • 没有验证:流式响应(生成器)里 after_request 与 teardown 的时机(见第 42 篇)、异步视图里的钩子、before_request 在 OPTIONS 预检请求上的表现(见第 24、112 篇)、蓝图嵌套时钩子的顺序
    京ICP备2026067502号-1京公网安备11010502063487号