当执行app.run()方法时,会调用werkzeug.serving 的 run_simple()方法,接着WSGI服务会调用app实例,app实例会执行"app. call _ _ 方法, __ call __方法调用app的wsgi_app方法,在wsgi_app中,会生成一个RequestContext类对象ctx,然后调用RequestContext类的push方法,(具体执行流程看: 2、ctx.push方法执行流程),将ctx对象放到local对象中,再根据路由分发执行视图函数,得到一个响应对象response(response响应过程,可以参考: 4.full_dispatch_request),最后无论成功与否,都会将ctx从local对象中移除
def wsgi_app(self, environ, start_response):
'''
1.1、request_context调用 RequestContext类
ctx是RequestContext类对象,里面包含了当前请求的request、session以及app
'''
ctx = self.request_context(environ)
error = None
try:
try:
'''
1.2
调用RequestContext类的push方法
把ctx对象放到flask自己写的local对象里的stack列表,通过线程id来区分
生成一个session对象,把ctx对象和app_ctx对象分别放在某一个列表中
'''
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
2、ctx.push方法执行流程
def push(self):
top = _request_ctx_stack.top
if top is not None and top.preserved:
top.pop(top._preserved_exc)
app_ctx = _app_ctx_stack.top
if app_ctx is None or app_ctx.app != self.app:
app_ctx = self.app.app_context()
app_ctx.push()
self._implicit_app_ctx_stack.append(app_ctx)
else:
self._implicit_app_ctx_stack.append(None)
if hasattr(sys, "exc_clear"):
sys.exc_clear()
_request_ctx_stack.push(self)
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)
if self.url_adapter is not None:
self.match_request()
3、LocalStack类中的push方法
先判断local对象是否有stack属性,没有则生成一个stack列表属性,将ctx对象添加在里面,将列表返回给RequestContext类。具体可以参考以下localstack类源码的注释
注意 :全局变量以下两个LocalStack不是同一个对象,虽然他们代码一样,但是,他们是两个不同的大字典,一个放ctx对象,一个放app_ctx对象,{'线程id号':{'stack':[ctx]}, },{'线程id号':{'stack':[app_ctx] }, }
具体原因,参考下面flask的local源码中的__init__ 初始化那部分代码
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
3.1、Local源码部分解析
class Local(object):
__slots__ = ("__storage__", "__ident_func__")
def __init__(self):
object.__setattr__(self, "__storage__", {})
object.__setattr__(self, "__ident_func__", get_ident)
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
.......
3.2、LocalStack类源码如下:
class LocalStack(object):
def __init__(self):
self._local = Local()
def __release_local__(self):
self._local.__release_local__()
........
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
def pop(self):
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()
@property
def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
4、full_dispatch_request方法执行流程
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)
4.1 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
4.2 preprocess_request方法
def preprocess_request(self):
bp = _request_ctx_stack.top.request.blueprint
funcs = self.url_value_preprocessors.get(None, ())
if bp is not None and bp in self.url_value_preprocessors:
funcs = chain(funcs, self.url_value_preprocessors[bp])
for func in funcs:
func(request.endpoint, request.view_args)
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
4.4 finalize_request方法
def finalize_request(self, rv, from_error_handler=False):
response = self.make_response(rv)
try:
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
flask目录结构
__init__.py :Flask框架的初始模块,创建Flask应用程序对象的入口。
app.py:定义了Flask应用的核心类,包括请求处理、URL路由、视图函数等。
globals.py:定义了一些全局变量和常量。
cli.py:定义了命令行接口相关的功能,如启动服务器等。blueprints.py:实现了蓝图(Blueprint)功能,用于组织和管理应用的模块化组件。
request.py:封装了请求对象,提供了方便的访问请求数据的方法。
session.py:封装了会话(Session)功能,用于在客户端和服务器之间存储和传递数据。
template.py:模板引擎相关的代码,用于渲染生成HTML页面。
views.py:定义了基于类的视图的实现。
helpers.py:定义了各种辅助函数,如URL生成、重定向等。
flask文件依赖关系
__init__.py是Flask的入口模块,它导入了其他核心模块和各种类、函数以及对象。
app.py依赖于__init__.py和其他模块,它使用了其中定义的类和函数来实现请求处理、路由等功能。
globals.py中定义的全局变量和常量可以被其他模块导入和使用。
cli.py依赖于__init__.py和其他模块,它通过命令行接口来管理应用程序的各种操作和配置。
blueprints.py提供了蓝图功能,其他模块可以导入该模块,并使用其中定义的类和函数来创建和注册蓝图。
request.py封装了请求对象相关的功能,其他模块可以导入其中的类和函数来处理请求数据。
session.py提供了会话功能,其他模块可以导入其中的类和函数来进行会话管理。
template.py实现了模板引擎功能,其他模块可以导入其中的类和函数来渲染生成HTML页面。
views.py实现了基于类的视图,其他模块可以导入其中的类和函数来定义和处理视图。
helpers.py提供了各种辅助函数,其他模块可以导入其中的函数来进行操作和功能扩展。