Flask请求钩子与上下文

Flask请求钩子与上下文对象

  1. 请求钩子

    在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:

    • 在请求开始时,建立数据库连接
    • 在请求开始时,根据需求进行权限校验
    • 在请求结束时,指定数据的交互格式

    为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。

    请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

    • before_first_request

      • 在处理第一个请求前执行
    • before_request

      • 在每次请求前执行
      • 如果在某修饰的函数中返回了一个响应,视图函数将不再被调用
    • after_request

      • 如果没有抛出错误,在每次请求后执行
      • 接受一个参数:视图函数作出的响应
      • 在此函数中可以对响应值在返回之前做最后一步修改处理
      • 需要将参数中的响应在此参数中进行返回
    • teardown_request:

      • 在after_request请求后执行
      • 接受一个参数:错误信息,如果有相关错误抛出
    • 代码实例

      from flask import Flask
      
      app = Flask(__name__)
      
      # 请求钩子
      # 在处理第一个请求前执行
      @app.before_first_request
      def before_first_request():
          print("before_first_request")
      
      # 在每一次请求之前调用
      @app.before_request
      def before_request():
          print("before_request")
      
      # 在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入
      @app.after_request
      def after_request(response):
          print("after_request")
          response.headers["Content-Type"] = "application/json"
          return response
      
      # 请每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
      @app.teardown_request
      def teardown_request(e):
          print("teardown_request")
      
      @app.route('/')
      def index():
          return 'Hello World'
      
      if __name__ == '__main__':
          app.run()
      
  2. 上下文对象
    1. 上下文

      上下文:即语境,语意,在程序中可以理解为在代码执行到某一时刻时,根据之前代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情。

      Flask中有两种上下文,请求上下文和应用上下文

      Flask中上下文对象:相当于一个容器,保存了 Flask 程序运行过程中的一些信息。

    2. 请求上下文(request context)
      1. 场景

        在视图函数中,如何取到当前请求的相关数据?比如:请求地址,请求方式,cookie等等

      2. 解决:

        在 flask 中,可以直接在视图函数中使用 request 这个对象进行获取相关数据,而 request 就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session

        • request
          • 封装了HTTP请求的内容,针对的是http请求。
        • session
          • 用来记录请求会话中的信息,针对的是用户信息。
    3. 应用上下文(application context)
      1. 介绍

        它的字面意思是应用上下文,但它不是一直存在的,它只是request context 中的一个对 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而生,随 request 而灭的。应用上下文对象有:current_app,g

      2. current_app对象
        1. 介绍

          应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

          • 应用的启动脚本是哪个文件,启动时指定了哪些参数
          • 加载了哪些配置文件,导入了哪些配置
          • 连了哪个数据库
          • 有哪些public的工具类、常量
          • 应用跑再哪个机器上,IP多少,内存多大
        2. 示例

          09flask_context中

          from flask import Flask, current_app
          
          app = Flask(__name__)
          app.secret_key = 'TPmi4aLWRbyVq8zu9v82dWYW1'
          
          class Config(object):
              REDIS = "redis://127.0.0.1/1"
          
          app.config.from_object(Config)
          
          @app.route('/')
          def index():
              return 'Hello World'
          
          from flask02.user import user_bp
          app.register_blueprint(user_bp, url_prefix="/user")
          
          
          if __name__ == '__main__':
              app.run()
          

          user模块代码

          from flask import Blueprint, current_app
          
          user_bp = Blueprint("user", __name__)
          
          # current_app获取配置信息
          @user_bp.route("/")
          def user():
              # redis://127.0.0.1/1
              print(current_app.config["REDIS"])
              # 09flask_context
              print(current_app.name)
              # 所有的路由信息
              print(current_app.url_map)
              return "user模块"
          
          @user_bp.route("/info")
          def user_info():
              return "user_info"
          
        3. 作用

          current_app 就是当前运行的flask app,在代码不方便直接操作flask的app对象时,可以操作current_app就等价于操作flask app对象

      3. g对象
        1. 介绍

          g 作为 flask 程序全局的一个临时变量,充当中间媒介的作用,我们可以通过它在一次请求调用的多个函数间传递一些数据。每次请求都会重设这个变量。

        2. 示例

          from flask import Flask, g
          
          app = Flask(__name__)
          
          def db_query():
              user_id = g.user_id
              user_name = g.user_name
              print('user_id={} user_name={}'.format(user_id, user_name))
          
          @app.route('/')
          def get_user_profile():
              g.user_id = 123
              g.user_name = 'xlz'
              db_query()
              return 'hello world'
          
      4. g对象与请求钩子的综合案例
        1. 需求

          • 构建认证机制
          • 对于特定视图可以提供强制要求用户登录的限制
          • 对于所有视图,无论是否强制要求用户登录,都可以在视图中尝试获取用户认证后的身份信息
        2. 实现

          from flask import Flask, session, g, abort
          
          app = Flask(__name__)
          app.secret_key = 'TPmi4aLWRbyVq8zu9v82dWYW1'
          
          @app.before_request
          def authentication():
              g.name = session.get("name")
          
          def login_required(func):
              def wrapper(*args, **kwargs):
                  if g.name is not None:
                      return func(*args, **kwargs)
                  else:
                      # abort(401)
                      return "请先登录"
              return wrapper
          
          @app.route('/login')
          def index():
              session["name"] = "xlz"
              return '登录用户'
          
          @app.route('/user')
          @login_required
          def get_user():
              return '你好,用户{}'.format(g.name)
          
          if __name__ == '__main__':
              app.run()
          
      5. app_context 与 request_context
        1. 场景

          在Flask程序未运行的情况下,调试代码时需要使用current_appgrequest这些对象,会不会有问题?该如何使用?

        2. app_context

          app_context为我们提供了应用上下文环境,允许我们在外部使用应用上下文current_appg

          ,可以通过with语句进行使用。

          from flask import Flask, current_app, g
          
          app = Flask(__name__)
          app.secret_key = 'TPmi4aLWRbyVq8zu9v82dWYW1'
          
          @app.route('/')
          def index():
              return 'Hello World'
          
          if __name__ == '__main__':
              # 构造一个应用上下文,在应用上下文中,curent_app和g可用, request和session不可用
              with app.app_context():
                  g.name = "xlz"
                  print(current_app.secret_key)
                  print(g.name)
          	app.run()
          
        3. request_context

          request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文requestsession,可以通过with语句进行使用。

          from flask import Flask, request, session, current_app, g
          
          app = Flask(__name__)
          
          
          @app.route('/')
          def index():
              return 'Hello World'
          
          if __name__ == '__main__':
              # 模拟解析客户端请求之后的wsgi字典数据
              environ = {
                  'wsgi.version': (1, 0),
                  'wsgi.input': '',
                  'REQUEST_METHOD': 'GET',
                  'PATH_INFO': '/',
                  'SERVER_NAME': 'itcast server',
                  'wsgi.url_scheme': 'http',
                  'SERVER_PORT': '80'
              }
              with app.request_context(environ):
                  print(request.path)
                  print(session.get("name"))
                  print(current_app)
                  print(g)
              app.run()
          
        4. test_request_context

          test_request_context允许我们在外部使用4个上下文对象,可以通过with语句进行使用

          from flask import Flask, request, session, current_app, g
          
          app = Flask(__name__)
          
          
          @app.route('/')
          def index():
              return 'Hello World'
          
          if __name__ == '__main__':
              # 在请求外面,使用请求上下文对象,报错
              # 如要使用可以构造一个测试的请求上下文,4个上下文对象都可用
              with app.test_request_context('/'):
                  print(request.url)
                  print(session.get("name"))
                  print(current_app)
                  print(g)
              app.run()
          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值