Flask Quick Start (13) - a request context

Before analyzing the flask project from start to end of the request is actually executed wsgi_app function in the "request process," also analyzed self.full_dispatch_request()the implementation of the view function request and request extensions. Now analyze other Source:

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)

1. ctx=self.request_context(environ)

def request_context(self, environ):
    return RequestContext(self, environ)

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
    self._implicit_app_ctx_stack = []
    self.preserved = False
    self._preserved_exc = None
    self._after_request_functions = []

Ctx RequestContext is an object that encapsulates some of the parameters, including the processing request, session ...

2. ctx.push()

ctx is RequestContext object is actually executed push method RequestContext, mainly to see the push method in the implementation of the _request_ctx_stack.push(self)method

def push(self):
    top = _request_ctx_stack.top
    if top is not None and top.preserved:
        top.pop(top._preserved_exc)
    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)
    if self.session is None:
        session_interface = self.app.session_interface
        self.session = session_interface.open_session(self.app, self.request)

        if self.session is None:
            self.session = session_interface.make_null_session(self.app)

    if self.url_adapter is not None:
        self.match_request()

What 2.1 _request_ctx_stack that?

_request_ctx_stackIt is LocalSrack () object, which means that _request_ctx_stack.push(self)the implementation of the push method LocalSrack, self is ctx (request related)

def push(self, obj):
    # 从self._local获取"stack"值,若为None,就设为空列表[];否则将obj即ctx放入“stack”的列表中去
    rv = getattr(self._local, "stack", None)  
    if rv is None:
        self._local.stack = rv = []
    rv.append(obj)
    return rv

self._localIt is the local object. No local stack attribute, the local execution of __getattr__()the method. This is the introduction to Part flask of local objects. To open up different storage space by a thread or coroutine id id, into related information request, session and so on. This enables multi-threaded or multi-coroutines

3. response = self.full_dispatch_request()

See "request process" articles, will not be repeated here Introduction

4. ctx.auto_pop(error)

def auto_pop(self, exc):
    if self.request.environ.get("flask._preserve_context") or (
        exc is not None and self.app.preserve_context_on_exception
    ):
        self.preserved = True
        self._preserved_exc = exc
    else:
        self.pop(exc)  # self是ctx,所以执行的是RequestContext的pop方法
        
def pop(self, exc=_sentinel):
    app_ctx = self._implicit_app_ctx_stack.pop() # self._implicit_app_ctx_stack = []
    try:
        clear_request = False
        if not self._implicit_app_ctx_stack:
            self.preserved = False
            self._preserved_exc = None
            if exc is _sentinel:
               exc = sys.exc_info()[1]
            self.app.do_teardown_request(exc)
            if hasattr(sys, "exc_clear"):
                sys.exc_clear()
            request_close = getattr(self.request, "close", None)  # 如果有request.close就执行request_close()方法
            if request_close is not None:
                request_close()
            clear_request = True
    finally:
        rv = _request_ctx_stack.pop()  # 主要是执行了这句
        if clear_request:
            rv.request.environ["werkzeug.request"] = None
        if app_ctx is not None:
            app_ctx.pop(exc)
        assert rv is self, "Popped wrong request context. (%r instead of %r)" % (rv,self,)

4.1 rv =_request_ctx_stack.pop()

Just mentioned _request_ctx_stack is LocalStack object, so that the execution of the pop method LocalStack

def pop(self):
    # self._local是Local对象,获取stack属性值,如果有就return stack[-1]
    stack = getattr(self._local, "stack", None)
    if stack is None:
        return None
    elif len(stack) == 1:
        release_local(self._local)
        return stack[-1]
    else:
        return stack.pop()

Summary: After the request is executing the pop out ctx request

Guess you like

Origin www.cnblogs.com/863652104kai/p/11704813.html