Flask框架整个流程源码解读

Posted Hank·Paul

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask框架整个流程源码解读相关的知识,希望对你有一定的参考价值。

Flask框架整个流程源码解读

"""
app.run()
本质执行的是 run_simple(ip,host,self)
self 是当前的app对象
app.__call__
"""

golbal文件,生成这些对象

_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"))

每一次有请求都会执行app.wsig_app(environ, start_response)

app.wsig_app源码:

    def wsgi_app(self, environ, start_response):
        # RequestContext的对象,其中包含当前请求的东西。
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                #RequestContext的对象,ctx.push,就执行是RequestContext对象的push方法
                #ctx放入local中
                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)

ctx = self.request_context(environ)做了什么?ctx=RequestContext的对象,里面有请求相关等所有东西:

# 1 我们self.request_context(environ)执行是:所以ctx是RequestContext(self, environ)的返回值:
        def request_context(self, environ):
            #等一下返回的ctx就是RequestContext()执行的结果。
            return RequestContext(self, environ)
#2 RequestContext(self, environ)的执行结果是什么?是RequestContext的对象,这个对象中包含了reuqest等信息
class RequestContext(object):
    #app, environ,ctx,就是RequestContext的对象,
    def __init__(self, app, environ, request=None, session=None):
        self.app = app
        if request is None:
            request = app.request_class(environ)
        self.request = request

ctx.push(),这里的ctx,是RequestContext的对象

#1 ctx.push方法就执行RequestContext的对象的push方法:
#源码:
    def push(self):
        #当前的self是RequestContext的对象,也就是ctx,
        _request_ctx_stack.push(self)
#2  _request_ctx_stack,我们发现它是全局LocalStack()的对象。
#_request_ctx_stack.push(self)就是执行LocalStack中的push方法,并且把ctx传给了#_request_ctx_stack.push的push方法。self=ctx
#LocalStack中的push源码:
  
    def push(self, obj):
        rv = getattr(self._local, "stack", None)
        if rv is None:
            #storage[线程,协程id]["stack"] = []
            self._local.stack = rv = []
        rv.append(obj)
        return rv
    
#上述代码中的self._local是Local对象,用来保证数据安全。
#当代码执行self._local.stack = rv = [],再Local对象中的存储结构是:storage[线程,协程id]["stack"] = []
# rv.append(obj),把storage[线程,协程id]["stack"] = [obj],又由于obj=ctx,就算就是把ctx放入到Local对象中。结构如下Local().storage[线程,协程id]["stack"] = [ctx]

response = self.full_dispatch_request()

#1
#这句话我们执行是请扩展与响应函数
#再响应函数和请求扩展中就可以使用request,它是如果和实现的呢?
from flask import Flask,request,session
app = Flask(__name__)
def index():
    print(request.method)
    print(session)
    return  "ok"
#比如上面代码中request.method,是如何拿到请求相关的内容呢?


#2

#我们点进去看request是什么?
request = LocalProxy(partial(_lookup_req_object, "request"))
#我们发现request就是 LocalProxy的对象。
#那我们再LocalProxy应该能找到method属性,但是发现没有,既然没有,它就一定写了__getattr__
#我们看__getattr__的源码:
 def __getattr__(self, name):
        #request.method,现在的name就是method
        if name == "__members__":
            return dir(self._get_current_object())
        #现在的name是method,self._get_current_object()执行结果就偏函数的执行结果
        #偏函数的执行结果中来获取method
        #偏函数的执行结果就是request.
        #etattr(request, method)
        return getattr(self._get_current_object(), name)
    
    
    
#3     
#我们再看看_get_current_object()它的执行结果是什么?
#self._get_current_object()的源码:
    def _get_current_object(self):
            return self.__local()       
#上面的self._get_current_object()执行结果就是self.__local()的执行结果


# 4 
#self.__local是什么?
#我们发现这个self.__local是实例化的时候传递的,也就local,代码如下
 def __init__(self, local, name=None):
        #self.__local= _LocalProxy__local=local = partial(_lookup_req_object, "request")
        #self.__local设置为隐藏属性,
        object.__setattr__(self, "_LocalProxy__local", local)
       # self.__local=local
    
#local是实例化的时候传递的。我们实例化这个 LocalProxy(partial(_lookup_req_object, "request"))
# 我们self._get_current_object=self.__local=local=partial(_lookup_req_object, "request")

#5
#那最终我们明白了:
def __getattr__(self, name):
        #request.method,现在的name就是method
        if name == "__members__":
            return dir(self._get_current_object())
        return getattr(self._get_current_object(), name)
    
#self._get_current_object() 执行结果,就partial(_lookup_req_object, "request")的执行结果。
#就是ctx.request,所以getattr(self._get_current_object(), name)相当于getattr(ctx.request, method)

#6 
#partial(_lookup_req_object, "request")()执行的结果
#_lookup_req_object的代码如下:

def _lookup_req_object(name):
    #这里的name,是"request"
    top = _request_ctx_stack.top
  
    #top是谁?是ctx.
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    #top里面找request,也就是top= ctx--》ctx里面找request.
    return getattr(top, name)

# 7 
#又因为_request_ctx_stack是LocalStack()的对象,所以 _request_ctx_stack.top就是执行LocalStack()的对象中的top:
#_request_ctx_stack.top的源码:
    @property
    def top(self):
        try:
            # storage[线程,协程id]["stack"] = [ctx]
            #现在top的retrun值就ctx
            return self._local.stack[-1]
        except (AttributeError, IndexError):
            return None
#代码中的self._local是Local对象,是我们存ctx的时候的Local对象。        

 

以上是关于Flask框架整个流程源码解读的主要内容,如果未能解决你的问题,请参考以下文章

Flask学习总结

Flask源码解读之路由部分

Tomcat启动过程源码解读

Flask 源码剖析 :Flask 启动流程

Flask 学习-88. jsonify() 函数源码解读深入学习

TiDB内核—源码剖析解读