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

时间:2023-03-08 16:23:15
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 :

 @setupmethod
def before_request(self, f):
self.before_request_funcs.setdefault(None, []).append(f)
return f

flask.app.Flask.before_request

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

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

 def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)

flask.app.Flask.wsgi_app

进到第 7 行的 full_dispatch_request 方法:

 def full_dispatch_request(self):
self.try_trigger_before_first_request_functions()
try:
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)

flask.app.Flask.full_dispatch_request

再进到第 5 行的 preprocess_request 方法:

 def preprocess_request(self):
bp = _request_ctx_stack.top.request.blueprint funcs = self.url_value_preprocessors.get(None, ())
if bp is not None and bp in self.url_value_preprocessors:
funcs = chain(funcs, self.url_value_preprocessors[bp])
for func in funcs:
func(request.endpoint, request.view_args) funcs = self.before_request_funcs.get(None, ())
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()
if rv is not None:
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 装饰器装饰的函数有返回值,那么将不会继续执行视图函数。