flask上下管理文相关 - RequestContetxt & AppContext对象

RequestContetxt / AppContext对象

1.flask程序启动时

当flask程序启动时,通过源码可知,首先会创建两个LocalStack对象,二者内部会分别创建Local对象(上篇文章已经介绍LocalStack)

from flask import globals
# 进入globals可以看到如下源码:
...
# context locals
# 创建
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()

current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

2.用户请求到来时

第一步:实例化RequestContext对象,封装数据,得到ctx对象

当用户请求到来时,执行Flask中的__call__方法,它的作用是将请求相关的数据交由wsgi进行初步封装

# Flask源码
class Flask(_PackageBoundObject):
        def __call__(self, environ, start_response):
        return self.wsgi_app(environ, start_response)

wsgi_app方法

# Flask源码
class Flask(_PackageBoundObject):
# wsgi_app封装请求信息
    def wsgi_app(self, environ, start_response):
        # 执行request_context方法,将请求相关的所有数据封装成一个 ctx 对象
        ctx = self.request_context(environ)       

request_context方法

class Flask(_PackageBoundObject):
        def request_context(self, environ):
        # 实例化RequestContext对象
        return RequestContext(self, environ)

RequestContext对象创建,封装request相关信息,主要是request和session;

class RequestContext(object):
    def __init__(self, app, environ, request=None, session=None):
        self.app = app
        if request is None:
            request = app.request_class(environ)
        self.request = request
        self.url_adapter = None
        try:
            self.url_adapter = app.create_url_adapter(self.request)
        except HTTPException as e:
            self.request.routing_exception = e
        self.flashes = None
        self.session = session

第二步:将ctx对象通过LocalStack,push到Local中进行保存

# Flask源码
class Flask(_PackageBoundObject):
# wsgi_app封装请求信息
    def wsgi_app(self, environ, start_response):
        # 执行request_context方法,将请求相关的所有数据封装成一个 ctx 对象
        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:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)

class RequestContext(object):
        def push(self):
            top = _request_ctx_stack.top
            if top is not None and top.preserved:
                top.pop(top._preserved_exc)
            # Before we push the request context we have to ensure that there
            # is an application context.
            app_ctx = _app_ctx_stack.top
            if app_ctx is None or app_ctx.app != self.app:
                app_ctx = self.app.app_context()
                app_ctx.push()
                self._implicit_app_ctx_stack.append(app_ctx)
            else:
                self._implicit_app_ctx_stack.append(None)

            if hasattr(sys, "exc_clear"):
                sys.exc_clear()

            _request_ctx_stack.push(self)  
            # 这里的就是通过flask启动时创建的_request_ctx_stack = LocalStack()进行push操作
            ...       

在上述代码中可以看到,执行_request_ctx_stack.push()操作之前,会先对app_ctx对象进行操作

app_ctx对象

class Flask(_PackageBoundObject):
def app_context(self):
return AppContext(self)

-  ```python
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()
      self._refcnt = 0

      def push(self):
          """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)
  • 从上述代码中可知,在app_ctx对象中封装的主要是app和g;后通过app_ctx.push()实际上是_app_ctx_stack.push(self)将自己push到Local中

3.执行视图函数

full_dispatch_request

class Flask(_PackageBoundObject):
        def wsgi_app(self, environ, start_response):
                response = self.full_dispatch_request()

弹出Local中的请求对象

视图函数执行完毕后,要将Local中的数据进行销毁工作

class Flask(_PackageBoundObject):
        def wsgi_app(self, environ, start_response):
            finally:
                if self.should_ignore_error(error):
                    error = None
                ctx.auto_pop(error)

wsgi源码

    def wsgi_app(self, environ, start_response):
        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:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
posted @ 2019-11-27 22:47  Aries-X  阅读(246)  评论(0编辑  收藏  举报