flask启动流程02

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

2.4 ctx.auto_pop(error)>>>>销毁ctx/app_ctx

def auto_pop(self, exc):
    if self.request.environ.get("flask._preserve_context") or (
        exc is not None and self.app.preserve_context_on_exception
    ):
        self.preserved = True
        self._preserved_exc = exc
    else:
		# 2.41 ctx 销毁
        self.pop(exc)
		
		
def pop(self, exc=_sentinel):
    
    ......
    finally:
	
		# 2.42ctx 执行LocalStack()的pop方法
        rv = _request_ctx_stack.pop()
		
		
        
        if clear_request:
            rv.request.environ["werkzeug.request"] = None


		# 2.43 执行app_ctx的pop方法,
        if app_ctx is not None:
            app_ctx.pop(exc)
			
			
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		class AppContext():
			def pop(self, exc=_sentinel):
				....
				
				finally:
				# 2.44 执行LocalStack()的pop方法
				rv = _app_ctx_stack.pop()
		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^	

2.42/2.44执行LocalStack的pop方法

*******************************************
# flask/globals.py文件
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
*******************************************

def pop(self):
    """Removes the topmost item from the stack, will return the
    old value or `None` if the stack was already empty.
    """
    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()
posted @ 2019-11-25 21:55  阿浪阿浪  阅读(563)  评论(0编辑  收藏  举报