Flask部分源码分析

1 前戏

1.1 werkzeug介绍

# Werkzeug是一个WSGI工具包。它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等。
# run_simple函数演示
    
# demo
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)
# 解释:
	run_simple()启动werkzeug服务,监听指定端口,请求来了则执行hello视图函数(对hello加括号执行)

1.2 偏函数

# partial()

# 例子:	
	fun = partial(_lookup_req_object, "request")
	# 即提前给函数_lookup_req_object传递了参数request,下次fun()就能直接调用函数,并且带有参数request

1.3threadLocal

# 查看文档《python之多线程下的threadLocal》

1.4代理模式

# 概念自己百度
# 应用:源码中的LocalProxy()

2 开始分析flask源码

2.1 启动flask项目

# 步骤1:
启动flask项目,运行app.run()


# 步骤2:查看run(),及核心代码为:
def run():
	  try:
            run_simple(t.cast(str, host), port, self, **options)
# 分析:
	1.self在这里是flask的对象,即app
    2.这一步相当于执行了app(),对象加括号调用相当于执行了类中的__call__方法
          
        
# 步骤3:查看flask的__call__方法
    def __call__(self, environ: dict, start_response: t.Callable) -> t.Any:
        return self.wsgi_app(environ, start_response)

    
# 步骤4:查看wsgi_app()
    def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
        ctx = self.request_context(environ)                 # 产生RequestContext对象,看2.2
        error: t.Optional[BaseException] = None
        try:
            try:
                ctx.push()								# 将ctx对象保存到local(),看2.3
                response = self.full_dispatch_request()	   # 执行视图函数,返回response对象,看2.5
            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)							# 最后,pop删除ctx

2.2 产生RequestContext对象

# ctx就是RequestContext对象,其中包含request对象,session和flash

# 步骤1:查看request_context()
    def request_context(self, environ: dict) -> RequestContext:
        return RequestContext(self, environ)
    
# 步骤2:查看RequestContext()
	class RequestContext:
        def __init__():
            self.app = app
            self.request = request
            self.flashes = None
            self.session = session
            
# 分析:
	ctx就等于类实例化得到RequestContext对象

2.3 将ctx保存到local()

# 将ctx对象保存到local(),以后访问request对象,就从local的ctx中拿,这样request才能保证线程安全。


# 步骤1:查看push(),核心代码:
	def push(self) -> None:
        _request_ctx_stack.push(self)
       
    
# 步骤2:查看_request_ctx_stack.push(self)
    def push(self, obj: t.Any) -> t.List[t.Any]:
        rv = getattr(self._local, "stack", []).copy()
        rv.append(obj)
        self._local.stack = rv
        return rv  # type: ignore
# 分析:
	1._request_ctx_stack是LocalStack()类的对象
	2.这里的self就是ctx
    3.push的功能:将ctx添加到Local()中。local = {"stack":[ctx]}

2.4 视图函数中访问request

# 不同线程访问request不会乱,因为每次的request都是从Local()中获取的# 步骤1:	全局的request,实际上是LocalProxy()的对象,执行的是类的__str__方法。    request = LocalProxy(partial(_lookup_req_object, "request"))    # 步骤2:最终会执行偏函数partial(_lookup_req_object, "request")	def _lookup_req_object(name):    	top = _request_ctx_stack.top    	if top is None:        	raise RuntimeError(_request_ctx_err_msg)    	return getattr(top, name)# 分析:	1.name就是request(字符串)    2.top就是ctx,反射出request对象    # 步骤3:查看_request_ctx_stack.top	@property    	def top(self) -> t.Any:        	try:            	return self._local.stack[-1]        	except (AttributeError, IndexError):            	return None# 分析:	1._request_ctx_stack是LocalStack()的对象,含有属性self._local = Local()    2.top是方法伪装成属性,返回Local().stack列表中的ctx

2.5 执行视图函数

# response = self.full_dispatch_request() 这一步开始执行视图函数# 步骤1:查看self.full_dispatch_request()	    def full_dispatch_request(self) -> Response:        	# 执行请求扩展before_first_request 			self.try_trigger_before_first_request_functions()        	try:            	request_started.send(self)						# 发送信号            	rv = self.preprocess_request()					# 执行请求扩展before_request            	if rv is None:								   # 判断请求扩展中是否有返回值                	rv = self.dispatch_request()        	except Exception as e:            	rv = self.handle_user_exception(e)				        	return self.finalize_request(rv)					# 真正的执行视图函数          # 步骤2:查看self.finalize_request(rv)	    def finalize_request():        response = self.make_response(rv)        try:            response = self.process_response(response)		  # 产生responsed对象,保存session            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
posted @ 2021-11-04 16:21  hai437  阅读(115)  评论(0编辑  收藏  举报