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
首先要知道在脚本加载时,被装饰器装饰的函数会被作为参数传入装饰器函数,在上面示例中也就是会将 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)
进到第 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)
再进到第 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
看到第 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 装饰器装饰的函数有返回值,那么将不会继续执行视图函数。
Java博客目录 | Python博客目录 | C#博客目录