flask 核心 之 应用上下文 及 请求上下文

版权声明:可以胡乱转载。 https://blog.csdn.net/hunyxv/article/details/84064533

Werkzeugs 是 Flask 的底层WSGI库。

什么是WSGI?

iOqdKS.jpg

一段简单的app:

def dispath_request(self, request):
    return Response('Hello World!')

def wsgi_app(self, environ, start_response):
    request = Request(environ)
    response = self.dispath_request(request)
    return response(environ, start_response)

environ: 包含全部的HTTP请求信息的字典,由WSGI Server解包 HTTP 请求生成。
**start_response:**一个WSGI Server 提供的函数,调用可以返回相应的状态吗和HTTP报文头,函数在返回前必须调用一次。

Flask的上下文对象

Flask有两种Context(上下文),分别是

  • RequestContext 请求上下文;
  • Request 请求的对象,封装了Http请求(environ)的内容,生命周期请求处理完就结束了;
  • Session 根据请求中的cookie,重新载入该访问者相关的会话信息;
  • AppContext 应用上下文;
  • g 处理请求时用作临时存储的对象。每次请求都会重设这个变量, 生命周期请求处理完就结束了;
  • current_app 当前激活程序的程序实例,只要当前程序还在运行就不会失效。

flask 处理请求和响应的流程:

iOXDVe.png

在 ‘flask/globals.py’ 代码中:

# context locals
_request_ctx_stack = LocalStack()   
# LocalStack 是由werkzeug提供的栈结构类提供了push、pop等方法
# 并且Local对象是werkzeug开发的类似 thinking.local(用于隔离不同线程间的全局变量) 对象,实现了在同一个协程中数据的隔离和全局性,具体怎么实现看源代码,暂时没看明白
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
# partial(_lookup_req_object, 'request') 总是返回 LocalStack 栈顶对象的 request 属性
# LocalProxy 用于代理Local对象和LocalStack对象,至于为什么使用代理。。
request = LocalProxy(partial(_lookup_req_object, 'request'))
session = LocalProxy(partial(_lookup_req_object, 'session'))
g = LocalProxy(partial(_lookup_app_object, 'g'))

flask local https://www.jianshu.com/p/3f38b777a621
为什么要使用 LocalProxy 而不直接使用 Local 和 LocalStack

# AppContext 应用上下文
#
# 在flask/app.py下:
#
def app_context(self):       # self 就是app对象
        return AppContext(self)

#
# 在 `flask/ctx.py` 代码中
#
class AppContext(object):
    def __init__(self, app):
        self.app = app
        self.url_adapter = app.create_url_adapter(None)
        self.g = app.app_ctx_globals_class()
        # Like request context, app contexts can be pushed multiple times
        # but there a basic "refcount" is enough to track them.
        self._refcnt = 0

    def push(self):           # 这个方法就是把应用上下文push到LocalStack,AppContext类有__enter__方法
        """Binds the app context to the current context."""
        self._refcnt += 1
        if hasattr(sys, 'exc_clear'):
            sys.exc_clear()
        _app_ctx_stack.push(self)
        appcontext_pushed.send(self.app)

#
# 在 flask/cli.py 中有
#
def with_appcontext(f):
    @click.pass_context
    def decorator(__ctx, *args, **kwargs):    # decorator 被装饰器后 _ctx 参数是 threading 的 local() 对象
        with __ctx.ensure_object(ScriptInfo).load_app().app_context():   # 在这里就把 应用上下文push到了LocalStack
            return __ctx.invoke(f, *args, **kwargs)
    return update_wrapper(decorator, f)

# RequestContext 请求上下文
#
#在flask/app.py下
#
def request_context(self, environ):     #  一次请求的环境变量
        return RequestContext(self, environ)

#
# 在flask/ctx.py下:
#
class RequestContext(object):
    def __init__(self, app, environ, request=None):
        self.app = app
        if request is None:
            request = app.request_class(environ)
        self.request = request
        self.url_adapter = app.create_url_adapter(self.request)
        self.flashes = None
        self.session = None
        ...
        ...
    def push(self):
          ...
          _request_ctx_stack.push(self)  

#
#在flask/app.py下
#
def wsgi_app(self, environ, start_response):              # 这里类似上面的那小段简单 Werkzeugs app
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)

到此从 AppContext 到 RequestContext 梳理完

参考资料:
Flask的核心机制!关于请求处理流程和上下文
Werkzeug(Flask)之Local、LocalStack和LocalProxy

猜你喜欢

转载自blog.csdn.net/hunyxv/article/details/84064533
今日推荐