Flask源码实现(0.1版本)笔记
Flask类
- 实现一个WSGI应用,扮演一个中心对象
- 通过传入应用的模块名或包名,一旦创建,将扮演有试图功能、URL规则、模版配置的注册中心
构造函数实现
def __init__(self, package_name):
# 是否启动调试,调试模式下当代码检测到改变将自动重载
self.debug = False
self.package_name = package_name
self.root_path = _get_package_path(self.package_name)
# 保存注册的所有视图函数的字典,key是函数名,value是函数对象
self.view_functions = {}
# 保存所有注册的错误处理的字典,key是错误代码整数,value是错误处理函数
self.error_handlers = {}
# 请求在dispatch之前要调用的函数列表
self.before_request_funcs = []
# 请求结束后要调用的函数列表,输入response对象,修改它,或替换它
self.after_request_funcs = []
# 用于填充模板上下文的没参数调用函数列表,每个都返回一个字典
self.template_context_processors = [_default_template_ctx_processor]
# 直接使用werkzeug的路由映射
self.url_map = Map()
# 如果设置了静态路径,加入路由映射
if self.static_path is not None:
self.url_map.add(Rule(self.static_path + '/<filename>',
build_only=True, endpoint='static'))
if pkg_resources is not None:
target = (self.package_name, 'static')
else:
target = os.path.join(self.root_path, 'static')
self.wsgi_app = SharedDataMiddleware(self.wsgi_app, {
self.static_path: target
})
# Jinja2环境
self.jinja_env = Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
self.jinja_env.globals.update(
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
装饰器app.route('/')
实现
给定的URL规则注册视图函数,变量部分作为视图函数的关键字参数传入
装饰器route()实现
def route(self, rule, **options):
def decorator(f):
self.add_url_rule(rule, f.__name__, **options)
self.view_functions[f.__name__] = f
return f
return decorator
处理URL尾部'/'的规则:
如果规则没有以'/'结尾,请求带'/',将引发404错误
如果规则是以'/'结尾,请求没有'/'的,将进行重定向带'/'的页面
装饰器可接受的参数
rule:URL规则字符串
methods:默认是GET,方法列表
subdomain:子域?
strict_slashes:禁用斜线规则
options:其他可以被转发到底层(
werkzeug.routing.Rule
类)的选项关联URL规则(
add_url_rule
)rule:URL规则字符串
endpoint:注册URL规则的endpoint,flask假设endpoint为视图函数名称
options:可以转发到底层类(
werkzeug.routing.Rule
)的选项支持的参数
方法实现:
def add_url_rule(self, rule, endpoint, **options):
options['endpoint'] = endpoint
options.setdefault('methods', ('GET',))
self.url_map.add(Rule(rule, **options))
wsgi_app()
方法实现
真实的WSGI应用,没有在__call__
中实现,可以使用中间件
def wsgi_app(self, environ, start_response):
"""The actual WSGI application. This is not implemented in
`__call__` so that middlewares can be applied:
app.wsgi_app = MyMiddleware(app.wsgi_app)
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
# 创建上下文
with self.request_context(environ):
# 预处理
rv = self.preprocess_request()
if rv is None:
# 调用URL对应的视图函数
rv = self.dispatch_request()
# 从视图的返回值转换为实际的响应对象
response = self.make_response(rv)
# 进行会话保存,以及调用所有after_request装饰器,返回response_class实例
response = self.process_response(response)
return response(environ, start_response)
可接收的参数
environ:WSGI环境
start_response:状态码、headers列表和可选的异常上下文,回调响应
视图函数返回值的类型
response_class:Response的类对象,直接返回,不改变
str:响应对象是字符串()
unicode:响应对象是使用utf-8编码的字符串
tuple:响应对象是元组
WSGI函数:调用WSGI应用,缓存响应对象
请求上下文类(_RequestContext
)
请求上下文包含所有请求相关的信息。在请求开始时创建,添加到
_request_ctx_stack
,并最后移除。会创建适合WSGI环境的URL适配器和request对象。
class _RequestContext(object):
"""The request context contains all request relevant information. It is
created at the beginning of the request and pushed to the
`_request_ctx_stack` and removed at the end of it. It will create the
URL adapter and request object for the WSGI environment provided.
"""
def __init__(self, app, environ):
self.app = app
self.url_adapter = app.url_map.bind_to_environ(environ)
self.request = app.request_class(environ)
# 创建或打开一个新的会话
self.session = app.open_session(self.request)
# g变量
self.g = _RequestGlobals()
self.flashes = None
def __enter__(self):
_request_ctx_stack.push(self)
def __exit__(self, exc_type, exc_value, tb):
# do not pop the request stack if we are in debug mode and an
# exception happened. This will allow the debugger to still
# access the request object in the interactive shell.
# 如果是调试模式或产生异常,将不移除请求,允许在交互式shell下继续访问request对象
if tb is None or not self.app.debug:
_request_ctx_stack.pop()
如果文章对您有帮助,请友情帮转发+点赞哦!