zoukankan      html  css  js  c++  java
  • 🍖Flask请求扩展及中间件

    一.请求扩展

    1.before_request

    • 作用 : before_request 相当于 django 中的 process_request,每一个请求在被处理前都会经过这个方法
    • 应用 : 用户登录认证(这样避免了每一个视图函数都加用户登录认证的装饰器)
    • 注意 : before_request 的返回值为 None 才会往后走, 否则直接返回你的返回值,如果定义了after_request那么会接着它执行, 最终本次请求响应结束
    • 示例
    from flask import Flask, request, render_template, session, url_for, redirect, flash, get_flashed_messages
    from markupsafe import Markup
    
    app = Flask(__name__)
    app.debug = True
    
    app.secret_key = 'the_secret_key'
    
    @app.before_request
    def process_request(*args, **kwargs):
        # 判断访问的是不是登入路径,是的话返回None继续往后走
        if request.path == '/login':
            return None
        else:
            # 不是的话判断是否携带用户信息(判断是否登入状态)
            username = session.get('username')
            print('username', username)
            if username:
                return None
            else:
                # 如果没有,则重定向到登入界面
                return redirect('/login')
    
    
    @app.route('/login')
    def login():
        username = request.args['username']
        print(username)
        if username == 'shawn':
            session['username'] = username
            return redirect('/index')
        else:
            return render_template('login.html')
    
    
    @app.route('/index')
    def index():
        return render_template('index.html')
    
    
    if __name__ == '__main__':
        app.run()
    

    2. after_request

    • 作用 : 类比django中间件中的process_response,如果请求没有出现异常的情况下, 会在请求返回return之前执行. 但是如果有多个顺序是从下往上执行.

    • 与Django中process_response的区别

    Django中当请求返回return后, 会从当前位置结束接着从当前位置response出去

    Flask中的after_request请求返回return之后, 后面的response也会一个个走完

    @app.after_request  # 后执行
    def process_response1(response):
        print('process_response1')
        return response
    
    @app.after_request  # 先执行
    def process_response2(response):
        print('process_response2')
        return response
    

    3.before_first_request

    • 作用 : 顾名思义, 项目启动第一次请求时触发执行
    • 应用 : 项目初始化用来保证以后项目只要不重启就不再继续执行
    @app.before_first_request
    def before_first():
        print("before_first")
    

    4. teardown_request

    • 效果 : 不管什么情况, 都会触发, 即便遇到了异常, 并且返回return没有任何效果, 无法控制返回结果
    • 应用 : 记录日志
    @app.teardown_request
    def ter(e):
        print("不管什么情况,都会触发,即便遇到了异常")
    

    5.errorhandler

    • 作用: 绑定错误的状态码进而可以捕获服务器的错误, 并返回对应的错误页面
    @app.errorhandler(404)
    def error_404(arg):
        return "404页面找不到了..."
    

    6.template_global

    • 作用: 全局的标签, 在任意的html页面中就可以直接使用, 不需要在render_template中传递参数以后才能使用
    @app.template_global()
    def gl(a1, a2):
        return a1 + a2
    
    # html 文件中使用
    {{ gl(1,2) }}
    

    7.template_filter

    • 作用: 全局的过滤器, 在任意的html页面中就可以直接使用, 不需要在render_template中传递参数以后才能使用
    @app.template_filter()
    def db(a1, a2, a3):
        return a1 + a2 + a3
        
    # html 文件中使用,相比较Django的过滤器最多只能传两个参数,这里可以传多个
    # 1传给a1,2-->a2,3-->a3
    {{ 1|db(2,3) }}
    

    8.示例

    • 测试1
    from flask import Flask, request, render_template, session, url_for, redirect, flash, get_flashed_messages
    
    from markupsafe import Markup
    
    app = Flask(__name__)
    app.debug = True
    
    app.secret_key = 'the_secret_key'
    
    
    @app.before_request
    def before_request(*args,**kwargs):
        print("before_request1")
        return 'before_request1'  # 这里return非None
    
    @app.before_request
    def before_request(*args,**kwargs):
        print("before_request2")  # 前面return非None,这里不走了
    
    @app.after_request
    def after_request(response):
        print("after_request1")  
        return response  # 后出去
    
    @app.after_request
    def after_request(response):
        print("after_request2")
        return response  # 先出去
    
    # 第一次请求的时候触发
    @app.before_first_request
    def before_first():
        print("before_first")
    
    @app.teardown_request
    def ter(e):
        print("不管什么情况,都会触发,即便遇到了异常")
    
    @app.route('/index')
    def index():
        return render_template('index.html')
    
    if __name__ == '__main__':
        app.run()
        
    """
    输出结果 : 
    before_first
    before_request1
    after_request2
    after_request1
    不管什么情况,都会触发,即便遇到了异常
    """
    
    • 测试2
    from flask import Flask, request, render_template, session, url_for, redirect, flash, get_flashed_messages
    
    from markupsafe import Markup
    
    app = Flask(__name__)
    app.debug = True
    
    app.secret_key = 'the_secret_key'
    
    @app.errorhandler(404)
    def error_404(arg):
        return "404页面找不到了..."
    
    @app.template_global()
    def gl(a1, a2):
        return a1 + a2
    
    @app.template_filter()
    def db(a1, a2, a3):
        return a1 + a2 + a3
        
    @app.route('/index')
    def index():
        return render_template('index.html')
    
    if __name__ == '__main__':
        app.run()
    
    <!--html-->
    
    <h2>{{gl(10, 20)}}</h2>
    <hr>
    <h2>{{10|db(10,10)}}</h2>
    
    
    • 效果

    templadasdas

    二.中间件

    1.自定义中间件

    • 严格来讲, flask中并没有中间件, 但是我们查看其源码可以模拟一个中间件
    from flask import Flask
    app = Flask(__name__)
    app.debug = True
    class MyMiddleware(object):
        def __init__(self, old_wsgi_app):
            self.old_wsgi_app = old_wsgi_app
    
        def __call__(self, environ, start_response):
            print('开始之前')
            ret = self.old_wsgi_app(environ, start_response)
            print('结束之后')
            return ret
    
    
    if __name__ == '__main__':
        app.wsgi_app = MyMiddleware(app.wsgi_app)
        app.run()
    

    1.源码分析

    • 我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app( ), app 是 Flask 类的对象, 对象加括号触发类中的__call__()方法, 也就是在执行app.__call__方法

    image-20210604172245123

    • 所以, 我们找到 Flask 类中的__call__()方法, 该方法直接返回了self.wsgi_app(environ, start_response)

    image-20210604172522598

    • 该返回值执行wsgi_app()方法, 接收environ(请求), start_response(响应), 也就是说 flask 中所有的内容调度都是从这里开始的, 这个方法就是程序的入口
    • 那么好办了, 我们想要实现中间件就必须在内重写wsgi_app()方法, 在该方法前后添加一些自己想要的功能
    • 定义一个中间件MyMiddleware, 在内部书写初始化方法__init__(), 用来接收原始的 app.wsgi对象并转成自己的对象
    • 因为 app+( ) 会触发类中 __call__( ) 方法, 所以在类中书写 __call__()方法, 里面重写wsgi_app()方法,于是你就可以在wsgi_app()方法前后进行自己功能的添加

    image-20210604175103489

    • 最后将自己的wsgi_app赋值给app对象完成替换

    image-20210604175202146

  • 相关阅读:
    BZOJ 4886 Lydsy1705月赛 叠塔游戏
    BZOJ 4552 TJOI2016&&HEOI2016 排序
    BZOJ 3702 二叉树
    BZOJ 4756 Usaco2017 Jan Promotion Counting
    BZOJ 4842 Neerc2016 Delight for a Cat
    BZOJ 1283 序列
    BZOJ 4819 SDOI2017 新生舞会
    BZOJ 1531 POI2005 Bank notes
    BZOJ 1925 SDOI2010 地精部落
    BZOJ WC2006 水管局长数据加强版
  • 原文地址:https://www.cnblogs.com/songhaixing/p/14851631.html
Copyright © 2011-2022 走看看