Flask钩子函数

钩子函数

1.什么是钩子函数

在正常执行的代码前后,插入一段想要执行的代码,这称为钩子函数.

2.Flask 中的钩子函数

上一篇分析了源码flask/app.py中的Flask()  类,其实它除了实现了应用上下文,请求上下文之外,还实现了一些常用的钩子hook 函数.

常见的钩子函数有:

钩子函数 描述
before_first_request 在处理第一个请求前执行,比如连接数据库操作
before_request 在每次执行请求前执行,比如权限校验
after_request 在每次请求之后调用,前提是没有异常抛出
errorhandler 在访问应用出错时,根据错误码,做一些定制
context_proceSSOr 上下文钩子,返回一个字典对象,可以在jinja 模板中使用
teardown_request 在响应销毁时,执行一个函数
teardown_appcontext 不管时候有异常,当应用上下文被移除时,执行的函数.

1.before_first_request

只有在处理第一次请求之前会执行,之后都不会执行.

应用场景:可以加载一些函数,用来对网站进行一些测试,检查,如果发现异常,则截断后续的请求,将整个Flask 应用停止运行.

from flask import Flask

app = Flask(__name__)
app.config.update({
 'DEBUG':True,
 'AUTO_TEMPLATES_RELOAD':True
})

@app.route('/')
def index():
 return 'Hello World!'

@app.before_first_request
def test_app():
 print('测试服务器运行')

if __name__ == '__main__':
 app.run()

输出:

127.0.0.1 - - "GET / HTTP/1.1" 200 -
测试服务器运行
127.0.0.1 - - "GET / HTTP/1.1" 200 -

2.before_request

在每个请求之前都会运行的钩子.

应用场景:共享session 的鉴权函数,请求黑白名单过滤,根据endpoint进行请求等.

from flask import Blueprint,request


bp = Blueprint('api',__name__,url_prefix='/api/')

required = {
 'api_register':['email','username','password']
}

@bp.before_request
def before():
 if not request.is_json:
     print(request.endpoint)
     print(request.json)
     return '请使用json风格的参数访问'
 try:
     if request.endpoint in required:
         if request.method == 'POST':
             missparam_list = [x for x in required[request.endpoint] if x not in request.json.keys()]
             if len(missparam_list) > 0:
                 return '缺少参数'
 except Exception as e:
     print(e)
 return "{}???".format(e)

@bp.route('/test/')
def test():
 if request.method == 'POST':
     return 'test'

@bp.route('/api_register/')
def register():
 return 'hello'

比如在验证session,来查看用户是否已经登录

from flask import Flask,session,g
from model.api import bp
from os import urandom

app = Flask(__name__)
app.config.update({
 'DEBUG':True,
 'AUTO_TEMPLATES_RELOAD':True,
 'SECRET_KEY':urandom(24)
})

@app.route('/')
def index():
 session['name']='Python'
 return 'Hello World!'

@app.before_first_request
def test_app():
 print('测试服务器运行')

app.register_blueprint(bp)

@app.before_request
def before():
 name = session.get('name')
 if name:
     g.name = name

@app.route('/first/')
def first():
 if g.name:
     return '已登录'
 else:
     return '请登录'

if __name__ == '__main__':
 app.run()

3.after_request

请求完成时执行,但是必须传入一个参数来接受响应对象,并在最后的return 这个参数,也就是响应内容.

场景:一般用于格式化响应结果,包括响应请求头,响应的格式等.

from flask import Flask,session,g
from model.api import bp
from os import urandom

app = Flask(__name__)
app.config.update({
 'DEBUG':True,
 'AUTO_TEMPLATES_RELOAD':True,
 'SECRET_KEY':urandom(24)
})

@app.route('/')
def index():
 session['name']='Python'
 return 'Hello World!'

@app.before_first_request
def test_app():
 print('测试服务器运行')

app.register_blueprint(bp)

@app.before_request
def before():
 name = session.get('name')
 if name:
     g.name = name

@app.route('/first/')
def first():
 if g.name:
     return '已登录'
 else:
     return '请登录'
@app.after_request
def after(response):
 response.headers['test']='test'
 return response

if __name__ == '__main__':
 app.run()

访问127.0.0.1/first/,查看响应头.

Flask钩子函数

4.errorhandler

当访问出错时,根据错误响应码,进行一些定制化的操作,比如返回404 页面.

场景: 定制化错误信息,404 ,500 等.

@app.errorhandler
def page_not_fond(error):
 return render_template('404.html'),404

访问不存在的页面时,它会返回定义的404.html

❯ curl http://127.0.0.1:5000/sdf
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

也可以在函数中手动抛出错误,这需要使用到abort() 函数

from flask import abort
@app.route('/app/')
def my_app()
 # 手动弹出一个错误
 abort(404)
 return 'test'

访问同样会访问到404.html

❯ curl http://127.0.0.1:5000/app/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>

5.context_processor

将一些数据按照字典的格式返回,可以在jinja 模板中使用.这样就不用在每个视图函数中都去返回一次render_template('xxx.html',info=xxx)

需要注意的是,这个函数必须返回一个字典对象,不管最后的判断函数是怎么样的.

场景:适用多个页面返回一个同样的值.比如登录后,在每个页面的标头都会显示用户的用户名.

# app.py
@app.context_processor
def context():
 # 表示登录
 if g.name:
     return {'username':'Jack'}
 else:
     return {}

@app.route('/test1/')
def test1():
 return render_template('test1.html')

@app.route('/test2/')
def test2():
 return render_template('test2.html')

test1.htmltest2.html 中接受username

{# test1.html, test2.html# }
{{ username}}

6.teardown_request

在响应销毁时,执行一个绑定的函数.

  • after_requtst:每一个请求之后绑定一个函数,如果请求没有异常
  • teardown_request:每一个请求之后绑定一个函数,即是有异常

场景:销毁数据库db 连接

@app.teardown_request
def teardown():
    db = getattr(g,'database',None)
    if db is not None:
        db.close()

7.teardown_appcontext

不管是否有异常,当app 的上下文被移除之后执行的函数,可以进行数据库的提交或者回滚.

@app.teardown_appcontext
def teardown(cmd=None):
 if cmd is None:
  db.session.commit()
 else:
  db.session.rollback()
 db.session.remove()

– END –


原文始发于微信公众号(Flask学习笔记):Flask钩子函数

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/36450.html

(0)

相关推荐

发表回复

登录后才能评论
半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!