Flask 中有几个处理 request 的装饰器, 分别为 before_request
, after_request
, errorhandler
和 teardown_request
. 简单的来讲对应为请求前执行, 请求正确执行后执行, 发生错误时执行, 返回 response 前执行.python
before_request
很好理解, 就是在处理路由规则对应的 view_function
以前执行的函数, 而且执行顺序是先绑定先执行, 而且先执行 flask app
的 before_request
, 再处理 blueprint
的 before_request
. 好比:flask
@app.before_request
def before_request_a():
print('I am in before_request_a')
@app.before_request
def before_request_b():
print('I am in before_request_b')
# 打印结果 -=-=-=-=-=-=-=-=-=-=-=-=-=
I am in before_request_a
I am in before_request_b
复制代码
可见源码:app
def preprocess_request(self):
"""Called before the request is dispatched. Calls :attr:`url_value_preprocessors` registered with the app and the current blueprint (if any). Then calls :attr:`before_request_funcs` registered with the app and the blueprint. If any :meth:`before_request` handler returns a non-None value, the value is handled as if it was the return value from the view, and further request handling is stopped. """
bp = _request_ctx_stack.top.request.blueprint
# 直接 register 在 flask app 上的 before_request
funcs = self.before_request_funcs.get(None, ())
# register 在 blueprint 上的 before_request
if bp is not None and bp in self.before_request_funcs:
funcs = chain(funcs, self.before_request_funcs[bp])
for func in funcs:
rv = func()
# 若是 before_request 有非空的返回, 都会直接做为 response 返回
if rv is not None:
return rv
复制代码
errorhandler
被触发的前提是 view_function
中抛出了错误, 而且错误码可以匹配上注册的 errorhandler
的错误码. 好比:函数
@app.errorhandler(500)
def error_handler(err):
print('I am in error_handler')
raise err
# 打印结果 -=-=-=-=-=-=-=-=-=-=-=-=-=
I am in error_handler
复制代码
after_request
被触发的前提是没有异常抛出; 或者异常被 errorhandler
接住并处理. 而且 after_request
执行的顺序是先绑定后执行. 好比:url
@app.after_request
def after_request_a(response):
print('I am in after_request_a')
return response
@app.after_request
def after_request_b(response):
print('I am in after_request_b')
return response
复制代码
方式一: errorhandler 可以 handle 抛出的异常spa
@app.errorhandler(500)
def error_handler(err):
print('I am in error_handler')
return 'ERROR PAGE'
# 打印结果 -=-=-=-=-=-=-=-=-=-=-=-=-=
I am in error_handler
I am in after_request_b
I am in after_request_a
复制代码
方式二: errorhandler 没法 handle 抛出的异常code
# 若是将 error_handler改成
@app.errorhandler(500)
def error_handler(err):
print('I am in error_handler')
raise err
# 打印结果 -=-=-=-=-=-=-=-=-=-=-=-=-=
I am in error_handler
复制代码
teardown_request
就和其他的三个不太同样了. 严格的来讲 teardown_request
没有固定的执行位置. 由于他直接和请求上下文环境挂钩. 只有在请求上下文被 pop
出请求栈的时候才会触发 teardown_request
, 因此即便以前有抛出错误的时候也会都会被执行, 执行完后返回 response.cdn
# flask/ctx.py
class RequestContext(object):
...
def pop(self, exc=_sentinel):
...
self.app.do_teardown_request(exc)
...
# flask/app.py
class Flask:
...
def do_teardown_request(self, exc=_sentinel):
...
funcs = reversed(self.teardown_request_funcs.get(None, ()))
bp = _request_ctx_stack.top.request.blueprint
if bp is not None and bp in self.teardown_request_funcs:
funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
for func in funcs:
func(exc)
...
复制代码
而且执行 teardown_request
的时候也是先绑定的后执行. 好比:blog
@app.teardown_request
def teardown_request_a(exc):
print('I am in teardown_request_a')
@app.teardown_request
def teardown_request_b(exc):
print('I am in teardown_request_b')
# 打印结果 -=-=-=-=-=-=-=-=-=-=-=-=-=
I am in teardown_request_a
I am in teardown_request_b
复制代码
因此总的来讲, 这几个装饰器装饰的方法执行的前后为 before_request
-> errorhandler
-> after_request
, teardown_request
在将当前请求 pop
出请求栈的时候执行. 如图所示: 路由