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

原文地址:https://www.cnblogs.com/daviddd/p/11930839.html

时间: 2024-10-08 17:28:02

flask启动流程02的相关文章

linux内核启动流程[转]

启动流程一览 既然启动是很严肃的一件事,那我们就来了解一下整个启动的过程吧! 好让大家比较容易发现启动过程里面可能会发生问题的地方,以及出现问题后的解决之道! 不过,由於启动的过程中,那个启动管理程序 (Boot Loader) 使用的软件可能不一样,例如目前各大 Linux distributions 的主流为 grub,但早期 Linux 默认是使用 LILO . 但无论如何,我们总是得要了解整个 boot loader 的工作情况,才能了解为何进行多重启动的配置时, 老是听人家讲要先安装

第二十章、启动流程、模块管理与 Loader grub

Boot Loader: Grub 『 boot loader 是加载核心的重要工具』!没有 boot loader 的话,那么 kernel 根本就没有办法被系统加载! boot loader 的两个 stage 在 BIOS 读完资讯后,接下来就是会到第一个启动装置的 MBR 去读取 boot loader 了.这个 boot loader 可以具有菜单功能.直接加载核心文件以及控制权移交的功能等, 系统必须要有 loader 才有办法加载该操作系统的核心.但是我们都知道, MBR 是整个硬

neutron-dhcp-agent服务启动流程

在分析nova boot创建VM的代码流程与neutron-dhcp-agent交互之前,首先分析neutron-dhcp-agent服务启动流程.与其他服务的启动入口一样.查看setup.cfg文件. [entry_points] console_scripts = neutron-db-manage = neutron.db.migration.cli:main neutron-debug = neutron.debug.shell:main neutron-dhcp-agent = neu

Linux启动流程简介以及各启动阶段失败的恢复方法

透彻的了解Linux启动流程是非常关键的知识点,只有了解了这部分内容,才会在Linux出现系统级别的错误时能够非常冷静的面对以及快速的排错. Linux启动流程 第一阶段 BIOS不是操作系统的职责范围 BIOS是硬件的功能,属于firmware BIOS存储于ROM,不需要强电就可以实现数据保存 更改BIOS如启动顺序保存在一种特定的RAM中,为了保证断电后实际更改保存,通过BIOS上加电池来解决 在BIOS可以选择启动顺序(硬盘,光盘,网络等) 如果选择BIOS从硬盘启动,硬盘的必须是MBR

istio组件介绍和启动流程

Istio各个Deployment包含的容器组件 Deployment 名称 Container和Port Container和Port istio-pilot pilot: 8080,15010 proxyv2: 15003,15005,15007 istio-galley galley: 443,9093 istio-egressgateway proxyv2: 80,443,15090 istio-ingressgateway proxyv2: 80,443,31400,15011,806

Linux系统入门---开机启动流程

目录 Linux系统入门---开机启动流程 一.centos6 二.systemd管理进程 1.查看级别 三.centos7实践案例: 1.案例1:centos7系统,单用户修改root密码 案例2: 如果修改级别 案例3:救援模式 四.修改CentOS7网卡名称为eth0和eth1 1.环境准备 2.用命令配置网卡 方法1: 方法2: 3.系统基本环境优化 五.Systemd 进程管理 1.systemctl管理服务的启动.重启.停止.重载.查看状态等常用命令 2.systemctl设置服务开

#24 centos6(RHEL)系列操作系统的启动流程、与命令chkconfig、grub的使用

所有由rc脚本关闭或启动的链接文件的原文件都存在于/etc/rc.d/init.d,系统为了方便使用,为此目录创建了链接/etc/init.d 所有/etc/inid.d(/etc/rc.d/init.d)目录中的脚本执行方式: # /etc/init.d/srv_script {start|stop|restart|status} # service srv_script {start|stop|restart|status} chkconfig命令: chkconfig - updates

#23 centos5(RHEL)系列操作系统的启动流程、与命令mkinitrd、dracut的使用

centos(RHEL)系列操作系统的启动流程:Intel x86兼容架构: Linux的系统组成:内核 + 应用程序  GUN/Linux:单纯的指Linux内核: 从硬盘存储和启动操作系统的角度: Linux的系统组成:内核 + 根文件系统(rootfs) 内核功能:进程管理,文件系统管理,内存管理,网络协议,驱动程序,安全功能,... Linux系统的系统运行环境可以分为两部分: 内和空间:内核代码(系统调用) 就是内核进程占用的CPU和内存资源的总和: 用户空间:应用程序(进程或线程)

CentOS 6开机启动流程实验篇

CentOS 6开机启动流程实验篇 centos 系统的启动流程 grub 破坏Linux的核心文件再修复体验系统启动流程 CentOS 6开机启动的具体详情请参见理论篇! 了解了系统启动的基本流程,以下我们通过"破坏式实验",即破坏系统启动过程中的一些关键环节,使系统无法启动,然后我们再通过修复这些文件使得系统正常重启,进而体验Linux系统的启动流程,这些关键环节包括破坏grub三个stage(stage1.stage1-5.stage2) 中的任何一个阶段,甚至是整个grub;