Flask -- 请求流程源码解析

源码流程文档下载

请求到来

项目启动后,当请求到来时,会执行 对象 + (), 执行__call__

def __call__(self, environ, start_response):
    return self.wsgi_app(environ, start_response)

跟踪到wsgi_app()

app.py

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)

注:以下步骤主要是基于上面的源码延伸出的。

一. 首先执行 ctx = self.request_context(environ),创建RequestContext对象,封装 request和session。

environ:是请求的原始数据

def request_context(self, environ):
    return RequestContext(self, environ)

# 相当于:ctx = RequestContext(environ) 实例化了一个对象
class RequestContext(object):
    """ctx对象中封装了 request和session"""
    request = app.Request(environ)
    self.request = request
    self.session = session

二. 执行 ctx.push(), 会将两个上下文对象添加到Local维护的字典中,是以 线程ID 为key, {‘stack’: []}} 为values。

2.1 首先会创建AppContext对象, 封装 app和g。

def push(self):
    app_ctx = self.app.app_context()
def app_context(self):
	return AppContext(self)

# 相当于app_ctx = AppContext()
class AppContext(object):
    """app_ctx对象封装了 app和g"""
    self.app = app
    self.g = app.app_ctx_globals_class()

2.2 执行app_ctx.push(),将app_ctx 对象添加到Local创建的字典中 {线程ID:{‘stack’: [app_ctx,]}}

ps:详见LocalStack 和 Local 实现上下文管理

_app_ctx_stack = LocalStack()
_app_ctx_stack.push(self)

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	

2.3 执行_request_ctx_stack.push(self), 将ctx 对象添加到另一个Local的 字典中 {线程ID:{‘stack’: [ctx,]}}

_request_ctx_stack = LocalStack()
_request_ctx_stack.push(self)

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

三. 执行response = self.full_dispatch_request(),主要是执行before/视图/after(处理session) .

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)

3.1 首先执行self.try_trigger_before_first_request_functions(),判断是否是第一次请求,然后循环执行列表中的before_first_request装饰的函数。

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

3.2 执行rv = self.preprocess_request(),主要是执行before_request装饰的函数, 这里使用了chain函数,迭代循环 app以及蓝图中的before_request装饰的函数。

from itertools import chain

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()		# 执行,rv接收返回值
    if rv is not None:
        # 如果有返回值,直接返回给用户,不再往下走
        return rv

3.3 执行rv = self.dispatch_request(), 主要是执行视图函数,

self.view_functions[rule.endpoint](**req.view_args)
# 通过view_functions={}中, endpoint与函数的对应关系去执行视图函数

3.4 执行self.finalize_request(rv), 执行after_request装饰的函数,并且j将session加密保存再cookie中。有返回值response。

def finalize_request(self, rv, from_error_handler=False):
    response = self.make_response(rv)
        try:
            response = self.process_response(response)
            # 执行
        return response

def process_response(self, response):
    funcs = chain(funcs, reversed(self.after_request_funcs[None]))
    # 获取after装饰的函数列表,进行反转
	for handler in funcs:
        # 循环执行
		response = handler(response)
	if not self.session_interface.is_null_session(ctx.session):
		self.session_interface.save_session(self, ctx.session, response)	# 保存session
	return response
    

四. 执行ctx.auto_pop(error), 主要是将数据返回给用户后,销毁 ctx/app_ctx 对象,以防止内存泄漏。

def auto_pop(self, exc):
	self.pop(exc)

def pop(self, exc=_sentinel):
	rv = _request_ctx_stack.pop()	# 将ctx对象删除
	app_ctx.pop(exc)	# 将app_ctx对象删除

总结:

  • 创建ctx = RequestContext对象,其内部封装了 Request对象和session数据。

  • 创建app_ctx = AppContext对象,其内部封装了App和g。

  • 然后ctx.push触发将 ctx 和 app_ctx 分别通过自己的LocalStack对象将其放入到Local中,Local的本质是以线程ID为key,以{“stack”:[]}为value的字典。

    {
    	1111:{“stack”:[ctx,]}
    }
    
    {
    	1111:{“stack”:[app_ctx,]}
    }
    
    

    注意:以后再想要获取 request/session / app / g时,都需要去local中获取。

  • 执行所有的before_request函数

  • 执行视图函数

  • 执行所有after_request函数(session加密放到cookie中)

  • 将数据返回给用户后,销毁ctx和app_ctx。

posted @ 2019-11-25 19:55  SensorError  阅读(95)  评论(0编辑  收藏  举报