美文网首页
flask 中几种在所有请求之前进行验证的方法之间的差别

flask 中几种在所有请求之前进行验证的方法之间的差别

作者: 那未必 | 来源:发表于2017-09-25 17:15 被阅读821次

    在所有请求之前添加钩子

    在做验证是否是登陆用户之类的功能时,一定会涉及到与此相关的知识点。

    对于直接用 app.add_url_rule() 或者使用 @app.route(...) 的方式来定义路由的情况,我们可以使用@app.before_request() 装饰器来实现在所有请求之前执行某一些验证逻辑代码。

    但是对于用blueprint来定义各种路由的方式,blueprint.before_request 不再是一个装饰器,而是一个函数,并且接受一个参数,参数是一个方法名 func。也就是在执行所有请求之前会先执行这个 func 方法

    最基本的代码是:

    def blueprint_validate_session_in_stock():
        print 'this is [before_request] in blueprint'
    
    def create_app(config_name):
        app=Flask(__name__)
        app.config.from_object(config.config['base'])
    
        stocks_blueprint.before_request(
            blueprint_validate_session_in_stock)
    
        app.register_blueprint(main_blueprint)
        app.register_blueprint(stocks_blueprint)
    
        return app
    
    

    这样的话,每次访问 stocks_blueprint 模块中的页面,都会打印:this is [before_request] in blueprint

    一个有益的对比

    由于 blueprint 不仅有 before_request() 方法,还有 before_app_request() 方法,还有 before_app_first_request() 方法,再加上在 app 层面还有 app.before_request() 方法。这四种方法究竟在哪些情况下执行?谁先谁后?这些问题都将直接影响到网站访问控制的逻辑,如果理解错误,还可能造成一些访问的死循环。

    我们将前面的代码改为:

    #encoding:utf8
    
    from flask import Flask,redirect
    import config
    
    from controllers import main_blueprint
    from controllers.stocks import stocks_blueprint
    
    
    def validate_session():
        print 'over the top! this is before_request\n'
    def blueprint_validate_app_session_in_stock():
        print '\tthis is [before_app_request] in blueprint\n'
    def blueprint_validate_app_session_first_in_stock():
        print '\tthis is [before_app_first_request] in blueprint\n'
    def blueprint_validate_session_in_stock():
        print '\tthis is [before_request] in blueprint\n'
        session=None
        if session==None:
            return redirect('/login')
    
    def create_app(config_name):
        app=Flask(__name__)
        app.config.from_object(config.config['base'])
    
        app.before_request(validate_session)
        stocks_blueprint.before_request(
            blueprint_validate_session_in_stock)
        stocks_blueprint.before_app_first_request(
            blueprint_validate_app_session_first_in_stock
        )
        stocks_blueprint.before_app_request(
            blueprint_validate_app_session_in_stock)
    
        app.register_blueprint(main_blueprint)
        app.register_blueprint(stocks_blueprint)
    
        # print app.url_map
        return app
    
    

    代码的意图是:访问 blueprint_stock 的根页面时,要做 session 验证,如果没有 session 就跳转到 login 页面去

    我们首先访问网站根页面,然后点击跳转到 stock 页面,所看到的打印记录是:

    # 这是访问网站根页面的反馈
    
        this is [before_app_first_request] in blueprint
    
    over the top! this is before_request
    
            this is [before_app_request] in blueprint
    
    127.0.0.1 - - [25/Sep/2017 11:45:59] "GET / HTTP/1.1" 200 -
    
    # 这是访问 stock 根页面的反馈
    
    over the top! this is before_request
    
            this is [before_app_request] in blueprint
    
            this is [before_request] in blueprint
    
    127.0.0.1 - - [25/Sep/2017 11:46:01] "GET /stocks/ HTTP/1.1" 302 -
    
    # 这是跳转到 login 页面的反馈
    
    over the top! this is before_request
    
            this is [before_app_request] in blueprint
    
    127.0.0.1 - - [25/Sep/2017 11:46:01] "GET /login HTTP/1.1" 200 -
    

    从上面的打印结果来对比,可以得出如下结论:

    • blueprint.before_app_request 会影响全局,即访问网站根页面或其他页面时,它都会生效

    • blueprint.before_app_request 会最先执行,先于 app.before_request

    • blueprint.before_app_first_request 会影响全局,但是只执行一次,适合用在初始化某些变量,它的执行顺序是在 app.before_request 之后

    • blueprint.before_app_request 要慎用,假如上面的代码中将验证 session 不存在就跳转到 login 页面的逻辑代码,写在了 blueprint_validate_app_session_in_stock() 中,就会造成访问的死循环! 因为访问 login 页面时,这个验证的逻辑代码同样会生效:发现没有 session,又一次跳转到 login 页面,造成页面一直在刷新!

    关于页面刷新

    如果用户停留在某一页面,只是在浏览器上点击了刷新,会有什么效果呢?我们将上面的代码中验证 session 不存在就跳转的 login 页面的代码去掉后,即注释掉这部分代码:

    #session=None
    #    if session==None:
    #        return redirect('/login')
    

    直接访问 blueprint_stock 的根页面来查看一下打印结果:

    # 这是第一次访问的打印结果
    
            this is [before_app_first_request] in blueprint
    
    over the top! this is before_request
    
            this is [before_app_request] in blueprint
    
            this is [before_request] in blueprint
    
    127.0.0.1 - - [25/Sep/2017 11:56:25] "GET /stocks/ HTTP/1.1" 200 -
    
    # 这是用户点击刷新后的打印结果:
    
    over the top! this is before_request
    
            this is [before_app_request] in blueprint
    
            this is [before_request] in blueprint
    
    127.0.0.1 - - [25/Sep/2017 11:56:48] "GET /stocks/ HTTP/1.1" 200 -
    

    可以看到,刷新后有两个变化:

    • 执行顺序变了,刷新后首先执行的是 app.before_request
    • 刷新后 blueprint.before_app_first_request 不执行了,这个很好理解

    结论

    • 一定要慎用 blueprint.before_app_request
    • blueprint 层面没有 before_first_request,如果要使用 blueprint.before_app_first_request 等同于 app.before_first_request 了,这个也要慎用。
    • 对于 blueprint.before_app_first_request 的应用场景是在各个 blueprint 中可以单独添加一些自己需要初始化的变量,各个 blueprint 中的这个操作相互是不会覆盖的,只是在 app 层面的 before_first_request 中做“加操作”,避免了直接修改 app.before_first_request 全局型代码在开发管理层面上带来的不便(假如app层面的代码和各个 blueprint 由不同的人维护)

    相关文章

      网友评论

          本文标题:flask 中几种在所有请求之前进行验证的方法之间的差别

          本文链接:https://www.haomeiwen.com/subject/lpedextx.html