> For the complete documentation index, see [llms.txt](https://flask-yushu.gitbook.io/yushu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flask-yushu.gitbook.io/yushu/4.flask-he-xin-ji-zhi/4.3-xiang-jie-flask-shang-xia-wen-yu-chu-ru-zhan.md).

# 4.3 详解flask上下文与出入栈

## Flask工作原理

![image.png](https://upload-images.jianshu.io/upload_images/7220971-cf45bd1876fcf08d.png?imageMogr2/auto-orient/strip|imageView2/2/w/1240)

1.当一个请求进入Flask框架，首先会实例化一个Request Context，这个上下文封装了请求的信息在Request中，并将这个上下文推入到一个栈(\_request\_ctx\_stack/\_app\_ctx\_strack)的结构中，即之前将的push方法

2.RequestContext在入\_request\_ctx\_stack之前，首先会检查\_app\_ctx\_strack是否为空，如果为空，则会把一个AppContext的对象入栈，然后再将这个请求入栈到\_request\_ctx\_stack中

3.我们的current\_app和request对象都是永远指向\_app\_ctx\_strack/\_request\_ctx\_stack的栈顶元素，也就是分别指向了两个上下文，如果这两个值是空的，那么LocalProxy就会出现unbound的状态

4.当请求结束的时候，这个请求会出栈-pop

## 回到我们之前的测试代码，如果要想让我们的测试代码正常运行，就需要手动将一个AppContext入栈。

```python
from flask import Flask, current_app


app = Flask(__name__)

# 获取AppContext，里面的代码很简单，就是：return AppContext(self)
ctx = app.app_context()
# 将AppContext入栈
ctx.push()
# 断点调试这里显示current_app=[LocalProxy]<LocalProxy unbound>
a = current_app

# RuntimeError: Working outside of application context.
b = current_app.config["DEBUG"]
print(b)
```

## 注意

虽然current\_app和request指向的是两个上下文，但是他们返回的却是Flask核心独享和Request对象。下面来看下这部分的源码

globals.py

```python
# globals.py中实例化LocalProxy获取current_app的代码中，传入了一个_find_app方法
current_app = LocalProxy(_find_app)

def _find_app():
    # 取栈顶元素
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    # 获取ctx中的app对象
    return top.app
```

从源码中可以看到，他获取的是app核心对象。
