zoukankan      html  css  js  c++  java
  • 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()
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    CentOS下安装中文man 手册
    CentOS 6.5系统安装配置图解教程
    a链接点击下载图片到本地(php)
    PHP 常用的header头部定义汇总
    thinkphp3.2接入支付宝支付接口(PC端)
    thinkphp3.2.3多图上传并且生成多张缩略图
    利用<meta http-equiv="refresh" content="0;URL=?id='.$id.'" />一条一条的更新数据
    【C/C++】C语言内存模型 (C memory layout)
    【软件工程】关于编程思想、学习方法
    【Python】opencv-python入门
  • 原文地址:https://www.cnblogs.com/daviddd/p/11930839.html
Copyright © 2011-2022 走看看