flask源码解析

 当执行app.run()方法时,会调用werkzeug.serving 的 run_simple()方法,接着WSGI服务会调用app实例,app实例会执行"app. call _ _ 方法, __ call __方法调用app的wsgi_app方法,在wsgi_app中,会生成一个RequestContext类对象ctx,然后调用RequestContext类的push方法,(具体执行流程看: 2、ctx.push方法执行流程),将ctx对象放到local对象中,再根据路由分发执行视图函数,得到一个响应对象response(response响应过程,可以参考: 4.full_dispatch_request),最后无论成功与否,都会将ctx从local对象中移除

def wsgi_app(self, environ, start_response):
    '''
    1.1、request_context调用 RequestContext类
    ctx是RequestContext类对象,里面包含了当前请求的request、session以及app
    '''
    ctx = self.request_context(environ)
    error = None
    try:
        try:
            '''
            1.2
           调用RequestContext类的push方法
           把ctx对象放到flask自己写的local对象里的stack列表,通过线程id来区分
           生成一个session对象,把ctx对象和app_ctx对象分别放在某一个列表中
            '''
            ctx.push()
            response = self.full_dispatch_request()
        except Exception as e:
            error = e
            response = self.handle_exception(e)
        except:
            error = sys.exc_info()[1]
            raise
        return response(environ, start_response)
    finally:
        if self.should_ignore_error(error):
            error = None
        ctx.auto_pop(error)

2、ctx.push方法执行流程

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

3、LocalStack类中的push方法

先判断local对象是否有stack属性,没有则生成一个stack列表属性,将ctx对象添加在里面,将列表返回给RequestContext类。具体可以参考以下localstack类源码的注释

注意 :全局变量以下两个LocalStack不是同一个对象,虽然他们代码一样,但是,他们是两个不同的大字典,一个放ctx对象,一个放app_ctx对象,{'线程id号':{'stack':[ctx]}, },{'线程id号':{'stack':[app_ctx] }, }
具体原因,参考下面flask的local源码中的__init__ 初始化那部分代码

_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()

3.1、Local源码部分解析

class Local(object):
    __slots__ = ("__storage__", "__ident_func__")
    def __init__(self):
        object.__setattr__(self, "__storage__", {})
        object.__setattr__(self, "__ident_func__", get_ident)
    def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)
    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value
        except KeyError:
            storage[ident] = {name: value}
    .......

3.2、LocalStack类源码如下:

class LocalStack(object):
    def __init__(self):
        self._local = Local()
    def __release_local__(self):
        self._local.__release_local__()
    ........
    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
    def pop(self):
        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()
    @property
    def top(self):
        try:
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None

4、full_dispatch_request方法执行流程

 def full_dispatch_request(self):
        self.try_trigger_before_first_request_functions()
        try:
            request_started.send(self)
            rv = self.preprocess_request()
            if rv is None:
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        return self.finalize_request(rv)

4.1 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

4.2 preprocess_request方法

def preprocess_request(self):
    bp = _request_ctx_stack.top.request.blueprint
    funcs = self.url_value_preprocessors.get(None, ())
    if bp is not None and bp in self.url_value_preprocessors:
        funcs = chain(funcs, self.url_value_preprocessors[bp])
    for func in funcs:
        func(request.endpoint, request.view_args)
    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

4.4 finalize_request方法

def finalize_request(self, rv, from_error_handler=False):
    response = self.make_response(rv)
    try:
        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

flask目录结构

__init__.py :Flask框架的初始模块,创建Flask应用程序对象的入口。

app.py:定义了Flask应用的核心类,包括请求处理、URL路由、视图函数等。

globals.py:定义了一些全局变量和常量。

cli.py:定义了命令行接口相关的功能,如启动服务器等。blueprints.py:实现了蓝图(Blueprint)功能,用于组织和管理应用的模块化组件。

request.py:封装了请求对象,提供了方便的访问请求数据的方法。

session.py:封装了会话(Session)功能,用于在客户端和服务器之间存储和传递数据。

template.py:模板引擎相关的代码,用于渲染生成HTML页面。

views.py:定义了基于类的视图的实现。

helpers.py:定义了各种辅助函数,如URL生成、重定向等。

flask文件依赖关系

__init__.py是Flask的入口模块,它导入了其他核心模块和各种类、函数以及对象。

app.py依赖于__init__.py和其他模块,它使用了其中定义的类和函数来实现请求处理、路由等功能。

globals.py中定义的全局变量和常量可以被其他模块导入和使用。

cli.py依赖于__init__.py和其他模块,它通过命令行接口来管理应用程序的各种操作和配置。

blueprints.py提供了蓝图功能,其他模块可以导入该模块,并使用其中定义的类和函数来创建和注册蓝图。

request.py封装了请求对象相关的功能,其他模块可以导入其中的类和函数来处理请求数据。

session.py提供了会话功能,其他模块可以导入其中的类和函数来进行会话管理。

template.py实现了模板引擎功能,其他模块可以导入其中的类和函数来渲染生成HTML页面。

views.py实现了基于类的视图,其他模块可以导入其中的类和函数来定义和处理视图。

helpers.py提供了各种辅助函数,其他模块可以导入其中的函数来进行操作和功能扩展。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值