• Flask快速入门(13) — 请求上下文1


    之前分析了flask项目从启动到请求结束实际是执行了wsgi_app函数,在“请求流程”中也分析了self.full_dispatch_request()是执行了请求的视图函数以及请求扩展。现在分析其它源码:

    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的一个对象,封装了一些参数,包括处理后的request、session...

    2. ctx.push()

    ctx是RequestContext对象,实际是执行了RequestContext的push方法,在push方法里主要看执行了_request_ctx_stack.push(self)方法

    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()
    

    2.1 _request_ctx_stack是什么?

    _request_ctx_stack是LocalSrack()的对象,也就是说_request_ctx_stack.push(self)执行的是LocalSrack的push方法,self就是ctx(请求相关的)

    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._local就是local对象。local中没有stack属性,所以执行local的__getattr__()方法。这就是flask上篇介绍到的local对象。通过线程id或协程id来开辟不同的存储空间,放入request、session等相关的信息。这样就可以实现多线程或多协程

    3. response = self.full_dispatch_request()

    请看“请求流程“篇,这里不再重复介绍

    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()

    刚刚提到过_request_ctx_stack是LocalStack对象,所以执行的是LocalStack的pop方法

    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()
    

    总结:在该请求执行完之后pop掉ctx请求

  • 相关阅读:
    Luogu4433:[COCI2009-2010#1] ALADIN(类欧几里德算法)
    Bzoj4766: 文艺计算姬(Matrix-tree/prufer)
    Bzoj5019: [Snoi2017]遗失的答案
    [HAOI2009]逆序对数列(加强)
    CF850F Rainbow Balls
    Luogu4887 第十四分块(前体)
    Luogu2483 [SDOI2010]魔法猪学院(可并堆)
    导数积分表
    Bzoj2395: [Balkan 2011]Timeismoney(最小乘积生成树)
    Min_25筛
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11704813.html
Copyright © 2020-2023  润新知