Request hooks in flask
2015-12-10什么是 request hooks
在 A request to flask 中我简单谈了下关于一个请求在 Flask 中生成的过程,已经提及到请求的预处理和请求的后处理。本文将会更加详细来说说关于这两者。
Request hooks 具体的实现方式是怎样的
以 before_first_request 为例来说,在使用 flask.Flask 类初始化生成时,会初始化一个存储所有使用 @before_first_request 注册的函数的列表: self.before_first_request_funcs = []。而当我们使用 @before_first_request 时,它的实际代码其实很简单:
@setupmethod
def before_first_request(self, f):
self.before_first_request_funcs.append(f)
return f
最后,当实际中请求时,在请求处理前,迭代 self.before_first_request_funcs 中的函数并一一调用即可。before_request 也是类似的思路,只不过用字典来存储相应的函数。为什么用字典呢, 因为还要涉及到 blueprint 的,所以用 blueprint 作为键来存储对应的 blueprint 的使用 @before_request 注册的函数,使用 None 为键来存储一般的 @before_request 注册的函数。 请求预处理时也是一一调用函数来进行指定的预处理操作。
所以简单地来说,就是:
- 初始化时生成存储容器(字典或是列表);
- 被装饰器装饰的函数将被加入到各自的容器中;
- 请求处理时,在合适的时间迭代调用注册的函数;
request hooks 的具体顺序
下面以 Flask 内置的 signal 为对比,来说明各个 request hooks 具体时在哪里执行的。一级列表是 Flask 中的 signal, 二级列表时各个 request hook,从上到下是依次顺序。
- appcontext_pushed
- before_first_request
- request_started
- before_request
- after_this_request, after_request
- request_finished
- teardown_request
- request_tearing_down
- teardown_appcontext
- appcontext_tearing_down
- appcontext_popped
一个丰满的例子
下面以一个简单的 Hello world 的例子加上各个 request hook 举一个例子,为了能有更加实际生动的印象。
from flask import Flask, after_this_request
app = Flask(__name__)
@app.before_first_request
def before_first_request_func():
print("I'm in the before_first_request_func.")
@app.before_request
def before_request_func():
print("I'm in the before_request_func.")
@app.route('/')
def index():
print("I'm in the view func: index.")
@after_this_request
def add_header(response):
print("I'm in the after_this_request func.")
response.headers['Python'] = 'Awesome'
return response
return "Hello, world."
@app.after_request
def after_request_func(response):
print("I'm in the after_request_func.")
return response
@app.teardown_request
def teardown_request_func(error):
print("I'm in the teardown_request_func.")
@app.teardown_appcontext
def teardown_appcontext_func(error):
print("I'm in the teardown_appcontext_func.")
if __name__ == '__main__':
app.run(debug=True)
当访问 https://localhost:5000/ 时,debug 信息是这样的:
I'm in the before_first_request_func. I'm in the before_request_func. I'm in the view func: index. I'm in the after_this_request func. I'm in the after_request_func. I'm in the teardown_request_func. I'm in the teardown_appcontext_func. 127.0.0.1 - - [28/Mar/2016 14:37:49] "GET / HTTP/1.1" 200 -
| [1] | 已经记不得是哪里看到的,抑或是自己取的名字 _(:3 |
| [2] | 严格意义上来说,before_first_request 注册的函数的调用发生在 request_started 这个 signal 之前的,而不属于 preprocess_request 这一过程;而在 preprocess_request 过程中还有包括 url_value_preprocessor 的处理, 但个人理解不能算是一个 request hooks, 所以这里并没有谈起。而不管是 teardown_request 还是 teardown_appcontext, 都是不属于 process_response 这一部分的,而是在 pop 对应的 context 时调用处理的。 |