Flask中current_app出现unbond的原因及解决

问题引出

  当使用current_app和request两个本地代理时,有时会出现处于unbond状态而无法使用的情况,本文对此问题的产生和解决作出分析。

 

Flask的核心机制

各部分解释

  • AppContext:应用上下文,对Flask核心对象进行了相关封装
  • RequestContext:请求上下文,对Request请求对象进行了相关封装
  • _app_ctx_stack:负责存放AppContext的线程隔离栈
  • _request_ctx_stack:负责存放RequestContext的线程隔离栈
  • current_app:取_app_ctx_stack栈顶的AppContext中的Flask核心对象
  • request:取_request_ctx_stack栈顶的RequestContext中的Request对象

 

请求过程

  1. 请求进入
  2. 封装请求对象Request为RequestContext
  3. 判断_app_ctx_stack是否为空,若为空或没有当前线程对应的AppContext则将app封装成一个AppContext推入栈中,否则不进行任何操作
  4. 再将RequestContext推入_request_ctx_stack
  5. 请求处理完毕后,AppContext与RequestContext都弹出栈

  (另1:Flask的核心对象app在全局范围内是唯一存在的,而每个线程都有自己对应的AppContext)

  (另2:current_app只是app的代理而不是真实的app,可以通过current_app._get_current_object()来获取真实的app)

 

  结论1:_app_ctx_stack和_request_ctx_stack不为空的条件是外界必须有请求进入

  结论2:current_app和request取的都是对应栈的栈顶元素,如果外界没有请求进入自然就出现了unbond状态

  结论3:当current_app和request在视图函数中使用时一般都没有问题(请求触发),如果在程序的其他地方或者做单元测试时使用则可能出现unbond状态(无请求进入)

 

解决方案

  current_app处于unbond状态的根本原因是_app_ctx_stack中并没有AppContext的存在,解决思路是既然Flask不能在没有请求的情况下将AppContext入栈,那么我们就将其手动推入栈中:

from flask import Flask,current_app
app = Flask(__name__)

ctx = app.app_context()    //生成一个AppContext对象
ctx.push()                 //手动入栈
# 相关操作代码放在这里
ctx.pop()                  //手动出栈

  

  在查看相关源码后我们可以发现AppContext其实是一个上下文管理器,于是可以使用python中的with语句来简化操作,with语句中的代码就可以正常使用current_app了:

from flask import Flask,current_app
app = Flask(__name__)

with app.app_context():
    # 相关操作代码放在这里

 

posted @ 2020-08-10 23:28  叶迩  阅读(425)  评论(0编辑  收藏  举报