在正常执行的代码前中后,强行插入执行一段你想要实现的功能的代码,这种函数就叫做钩子函数。钩子函数就是等同于高速公路上的收费站,进高速之前给你一个卡,并检查你是否超重。离开之前收你,也可以拦住你安检一下。
一、基础概念:
● request: Flask的请求上下文,包含请求变量如:method、args、form、values、endpoint、headers、remote_addr都是比较常用的。● session:Flask的请求上下文,用于存放用户的会话信息。
● current_app:Flask的应用上下文,返回当前app的方法和属性,可以勉强理解为类全局变量。
二、七种钩子
第一个钩子:@app.before_first_request
只在第一次请求之前执行,也就是启动项目,不会执行,只会在第一次有人发起请求时,才会触发这个钩子中的代码。
全局场景:可以带动一个异步执行的函数,进行一些健康指标的检查,如果发现有异常,则截断后续的请求,将整个Flask应用停止。
@app.before_first_request
def first_request():
print('只有在处理第一次请求之前执行')
第二个钩子:@app.before_request
这是最重要的一个钩子,在每次请求之前可以注入你要的逻辑的钩子。在app下的before_request,过滤的是全部请求。结合Blueprint的before_request,则是过滤该蓝图下的请求。所以我们就可以进行分层过滤,定制化过滤。
全局的场景包含:共享session的鉴权函数、请求黑白名单过滤、根据endpoint进行请求j等。
蓝图场景包含api的请求必填字段校验,是否json请求校验,请求的token校验等。
api = Blueprint('api', __name__)
requied = {
'api.register':['email','username','password']
}
# 钩子 在请求执行之前
@api.before_request
def before_request():
# 请求格式校验拦截
if not request.is_json:
return '带参数请求请使用json格式'
# 缺少必填参数拦截
try:
if request.endpoint in requied:
if request.method == "POST":
missparam_list = [x for x in requied[request.endpoint] if x.encode('utf8') not in list(parse.parse_qs(request.data).keys())]
else:
missparam_list = [x for x in requied[request.endpoint] if x not in request.json.keys()]
if len(missparam_list) > 0:
return "缺少以下参数:{0}"
except Exception as e:
app.logger.error(e)
return "{0}".format(e)
第三个钩子:@app.errorhandler
当访问应用出错时,根据错误响应码,进行一些定制化的操作,如返回一个可爱的404页面。也可以进行一些报错登记。
场景:可以用redis进行错误请求计数,超过一定量则进行告警。可以重定向到一个定制的错误代码页面等。
@app.errorhandler(404)
def page_not_found(error):
return render_template('otherpage/404.html'),404
第四个钩子:@app.context_processor
这个钩子也很实用,是将一些常量按字典的格式返回,则可以在jinja2的模版中引用。这样就不用在每个视图函数中都render_template中重复去写一次。代码更简洁。
场景:在html中,直接用{{jidan}}就会在页面显示yao。等同于app.add_template_global('yao',''jidan)
@app.context_processor
def context_rocessor():
return {'jidan':'yao'}
第五个钩子:@app.after_request
和上个钩子类似,差别在于是请求完成时执行,它和之前钩子有点不同,必须传入一个参数来接收响应对象,并在最后return 这个参数,也就是返回响应内容。
场景:一般用于格式化响应结果,包括响应请求头,响应的格式等。
@app.after_request
def after_request(response):
response.headers['jidan'] = 'yaoyao'
return response
第六个钩子:@app.teardown_request
和第五个钩子功能类似,在响应销毁时,执行一个绑定的函数。做一些操作。
区别点在于:
● after_request: 每一个请求之后绑定一个函数,如果请求没有异常。● teardown_request: 每一个请求之后绑定一个函数,即使遇到了异常。
场景:销毁DB连接等。
@app.teardown_request
def teardown_db(exception):
db = getattr(g, 'database', None)
if db is not None:
db.close()
第七个钩子:@app.teardown_appcontext
之前介绍的大部分是请求上下文的钩子,这个属于应用上下文的钩子。不管是否有异常,当APP上下文被移除之后执行的函数, 可以进行数据库的提交或者回滚。
场景:DB事务操作。
@app.teardown_appcontext
def teardown(cmd=None):
if cmd is None:
db.session.commit()
else:
db.session.rollback()
db.session.remove()