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 會先執行。flask

源碼

查看 before_request :app

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 中。ide

緊接着,在請求到來時,會執行 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 方法:url

 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 方法:spa

 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 行接收到返回值,第 六、7 行判斷若是返回值若是爲空,才執行 self.dispatch_request 方法。而 self.dispatch_request 方法正是用來執行視圖函數的。因此得出結論:若是 before_request 裝飾器裝飾的函數有返回值,那麼將不會繼續執行視圖函數。3d

相關文章
相關標籤/搜索