python框架之Flask(5)-@app.before_request原理

示例

from flask import Flask

app = Flask(__name__)


@app.before_request
def xx():
    pass


@app.route('/')
def index():
    return 'index'


if __name__ == '__main__':
    app.run()

看如上代码,如果此时请求视图函数 index ,在视图函数执行之前, @app.before_request 装饰的函数在这里也就是 xx 会先执行。

源码

查看 before_request :

1 @setupmethod
2 def before_request(self, f):
3     self.before_request_funcs.setdefault(None, []).append(f)
4     return f
flask.app.Flask.before_request

首先要知道在脚本加载时,被装饰器装饰的函数会被作为参数传入装饰器函数,在上面示例中也就是会将 xx 函数作为 before_request 函数的参数 f 传入。可以看到该装饰器函数就很简单两行,把函数 f 句柄添加到 app.before_request_funcs 列表中,对应示例中就是将 xx 函数的句柄添加到了 before_request_funcs 中。

紧接着,在请求到来时,会执行 app.wsgi_app 方法:

 1 def wsgi_app(self, environ, start_response):
 2     ctx = self.request_context(environ)
 3     error = None
 4     try:
 5         try:
 6             ctx.push()
 7             response = self.full_dispatch_request()
 8         except Exception as e:
 9             error = e
10             response = self.handle_exception(e)
11         except:
12             error = sys.exc_info()[1]
13             raise
14         return response(environ, start_response)
15     finally:
16         if self.should_ignore_error(error):
17             error = None
18         ctx.auto_pop(error)
flask.app.Flask.wsgi_app

进到第 7 行的 full_dispatch_request 方法:

 1 def full_dispatch_request(self):
 2     self.try_trigger_before_first_request_functions()
 3     try:
 4         request_started.send(self)
 5         rv = self.preprocess_request()
 6         if rv is None:
 7             rv = self.dispatch_request()
 8     except Exception as e:
 9         rv = self.handle_user_exception(e)
10     return self.finalize_request(rv)
flask.app.Flask.full_dispatch_request

再进到第 5 行的 preprocess_request 方法:

 1 def preprocess_request(self):
 2     bp = _request_ctx_stack.top.request.blueprint
 3 
 4     funcs = self.url_value_preprocessors.get(None, ())
 5     if bp is not None and bp in self.url_value_preprocessors:
 6         funcs = chain(funcs, self.url_value_preprocessors[bp])
 7     for func in funcs:
 8         func(request.endpoint, request.view_args)
 9 
10     funcs = self.before_request_funcs.get(None, ())
11     if bp is not None and bp in self.before_request_funcs:
12         funcs = chain(funcs, self.before_request_funcs[bp])
13     for func in funcs:
14         rv = func()
15         if rv is not None:
16             return rv
flask.app.Flask.preprocess_request

看到第 10 行,从 self.before_request_funcs 拿到之前存入的方法,也就是也就是上面被 before_request 装饰器装饰的函数对应示例中的 xx ,接着在 13-16 行循环执行所有方法,如果有返回值则直接返回,到这里 before_request 的执行原理也就明了了。紧接着 flask.app.Flask.full_dispatch_request 中第 5 行接收到返回值,第 6、7 行判断如果返回值如果为空,才执行 self.dispatch_request 方法。而 self.dispatch_request 方法正是用来执行视图函数的。所以得出结论:如果 before_request 装饰器装饰的函数有返回值,那么将不会继续执行视图函数。

posted @ 2018-11-29 10:26  zze  阅读(837)  评论(0编辑  收藏  举报