三类钩子什么时候触发、触发几次、顺序如何、出了异常还跑不跑?这篇把各种请求都跑一遍,用事件顺序说话。
钩子定义(简写):
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)最后执行的 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
test_client 向上抛出了: ValueError boom before_1 → before_2 → view → teardown_2(ValueError) → teardown_1(ValueError)