Flask 中 before_request, after_request, errorhandler 和 teardown_request 执行顺序

Flask 中有几个处理 request 的装饰器, 分别为 before_request, after_request, errorhandlerteardown_request. 简单的来说对应为请求前执行, 请求正确执行后执行, 发生错误时执行, 返回 response 前执行.

before_request

before_request 很好理解, 就是在处理路由规则对应的 view_function 之前执行的函数, 并且执行顺序是先绑定先执行, 并且先执行 flask appbefore_request, 再处理 blueprintbefore_request. 比如:

@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
复制代码

可见源码:

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

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

after_request 被触发的前提是没有异常抛出; 或者异常被 errorhandler 接住并处理. 并且 after_request 执行的顺序是先绑定后执行. 比如:

@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 抛出的异常

@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 抛出的异常

# 如果将 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 就和其余的三个不太一样了. 严格的来说 teardown_request 没有固定的执行位置. 因为他直接和请求上下文环境挂钩. 只有在请求上下文被 pop 出请求栈的时候才会触发 teardown_request, 所以即使之前有抛出错误的时候也会都会被执行, 执行完后返回 response.

# 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 的时候也是先绑定的后执行. 比如:

@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 出请求栈的时候执行. 如图所示:

转载于:https://juejin.im/post/5cefc3d35188252dda0b03a8

你可能感兴趣的:(Flask 中 before_request, after_request, errorhandler 和 teardown_request 执行顺序)