flask启动流程02

Posted daviddd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask启动流程02相关的知识,希望对你有一定的参考价值。

flask请求到达流程

1.0 app启动后,浏览器发送请求触发app.__call__()方法

#1. 执行__call__方法,
def __call__(self, environ, start_response):
    """The WSGI server calls the Flask application object as the
    WSGI application. This calls :meth:`wsgi_app` which can be
    wrapped to applying middleware."""
    return self.wsgi_app(environ, start_response)

2.0 wsgi_app方法详解

def wsgi_app(self, environ, start_response):

    # 2.1创建请求上下文ctx = RequestContext对象
    ctx = self.request_context(environ)
    error = None
    try:
        try:
            # 2.20 创建应用上下文 app_ctx = AppContext对象,
            # 2.21 将应用上下文维护成一个栈
            # 2.22 将请求上下文维护成一个栈
            # 2.23 创建session
            # 2.24 路由匹配
            ctx.push()
            
            
            # 2.30 触发所有的@app.before_first_request,只有启动程序后,
            #      第一个请求到来时执行
            # 2.31 执行所有的@app.before_request,有返回值则直接返回给用户,不执行
            #      下面的操作,无返回值则继续执行
            # 2.32 执行所有的视图函数
            # 2.33 执行所有的@app.after_request,
            # 2.34 保存session
            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
        
        # 2.4 销毁ctx/app_ctx
        ctx.auto_pop(error)

2.1 创建请求上下文ctx = RequestContext对象

# 实例化ResquestContext对象
class Flask():
    def request_context(self, environ):
        return RequestContext(self, environ)
    
# 封装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
        

2.20~24 ctx.push()方法

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
    
    # 创建应用上下文 app_ctx = AppContext对象
    if app_ctx is None or app_ctx.app != self.app:
        app_ctx = self.app.app_context()

    *********************************************************
    class Flask():
        def app_context(self):
            return AppContext(self)
    *********************************************************
    
    # 2.21 调用app_ctx对象的push方法,将应用上下文维护成一个栈
    

        app_ctx.push()
        
        $$$$$$$$$$$$$$$$$$$$$$$app_ctx.push()过程$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
        class AppContext():
            ...
            def push(self):
                self._refcnt += 1
                if hasattr(sys, "exc_clear"):
                    sys.exc_clear()
                # 2.211执行LocalStack实例化对象.push 方法
                _app_ctx_stack.push(self)
                appcontext_pushed.send(self.app)
                
        
        # flask/globals.py文件
        _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.212 将其维护成一个—_local(Local())的一个栈
        class LocalStack():
            def push(self, obj):
                """Pushes a new item to the stack"""
                rv = getattr(self._local, "stack", None)
                if rv is None:
                    self._local.stack = rv = []
                rv.append(obj)
                return rv
                    
    $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
    
    
    
        self._implicit_app_ctx_stack.append(app_ctx)
    else:
        self._implicit_app_ctx_stack.append(None)

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

    # 2.22 将请求上下文维护成一个栈,同应用请求文一样
    _request_ctx_stack.push(self)


    # 2.23 创建session    
    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)
    # 2.24 路由匹配
    if self.url_adapter is not None:
        self.match_request()

2.30~2.32 response = self.full_dispatch_request()

def full_dispatch_request(self):

    # 2.30 触发所有的@app.before_first_request,只有启动程序后,
    #      第一个请求到来时执行.
    self.try_trigger_before_first_request_functions()
    
    ########################################################
    
    def try_trigger_before_first_request_functions(self):
    
        if self._got_first_request:
            return
        with self._before_request_lock:
            if self._got_first_request:
                return
            for func in self.before_first_request_funcs:
                func()
            self._got_first_request = True
    ########################################################
    
    
    
    
    try:
        request_started.send(self)
        
        
        # 2.31 执行所有的@app.before_request,有返回值则直接返回给用户,不执行
        #      下面的操作,无返回值则继续执行.
        rv = self.preprocess_request()
        
        """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
        def preprocess_request(self):
        
            funcs = self.before_request_funcs.get(None, ())
            if bp is not None and bp in self.before_request_funcs:
                funcs = chain(funcs, self.before_request_funcs[bp])
            for func in funcs:
                rv = func()
                if rv is not None:
                    return rv
                    
        """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
        
        
        
        if rv is None:
            # 2.32 执行所有的视图函数
            rv = self.dispatch_request()
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            def dispatch_request(self):
                return self.view_functions[rule.endpoint](**req.view_args)
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    except Exception as e:
        rv = self.handle_user_exception(e)
        
    #2.33~2.34
    return self.finalize_request(rv)

2.33~2.34 self.finalize_request(rv)

def finalize_request(self, rv, from_error_handler=False):
    response = self.make_response(rv)
    try:
        # 2.33 执行所有的@app.after_request,
        response = self.process_response(response)
        
        request_finished.send(self, response=response)
    except Exception:
        if not from_error_handler:
            raise
        self.logger.exception(
            "Request finalizing failed with an error while handling an error"
        )
    return response

# 遍历_after_request_functions,执行所有的after_request
def process_response(self, response):
    ctx = _request_ctx_stack.top
    bp = ctx.request.blueprint
    funcs = ctx._after_request_functions
    if bp is not None and bp in self.after_request_funcs:
        funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
    if None in self.after_request_funcs:
        funcs = chain(funcs, reversed(self.after_request_funcs[None]))
    for handler in funcs:
        response = handler(response)
        
    # 2.34 保存session
    if not self.session_interface.is_null_session(ctx.session):
        self.session_interface.save_session(self, ctx.session, response)
    return response

以上是关于flask启动流程02的主要内容,如果未能解决你的问题,请参考以下文章

Flask 源码剖析 :Flask 启动流程

Flask启动原理,源码流程分析

为啥不每次 Flask 启动时生成密钥?

Flask源码流程分析

flask请求流程

springboot启动流程构造SpringApplication实例对象