flask基础之app初始化(四)
前言
flask的核心对象是Flask,它定义了flask框架对于http请求的整个处理逻辑。随着服务器被启动,app被创建并初始化,那么具体的过程是这样的呢?
系列文章
一个最基本web应用的flask代码
from flask import Flask
import os
# 创建app对象
app = Flask(__name__,template_folder='static/html')
# 加载配置文件
app.config['SECRET_KEY'] = '123'
# 加载蓝图
app.register_blueprint(rest, url_prefix='')
# 加载请求钩子
@rest.before_request
def rest_test():
print('this is a test')
pass
# 定义api处理视图
@app.route('/test1')
def test():
return 'OK'
@定义错误处理逻辑
@app.errorhandler(400)
def handle_errer(errer):
print(errer)
return errer
if __name__ == '__main__':
app.run(host='127.0.0.1', port=80, debug=True)
如上所示,一个完整的web应用所拥有的最基本的东西就这些了,我们一步步分析。
第一步:创建Flask对象
创建一个Flask的app对象作为备用是一切的开端,看一下初始化干了什么?
class Flask(_PackageBoundObject):
request_class = Request # 指定请求对象
response_class = Response # 指定响应对象
jinja_environment = Environment # 指定前端模板语言环境
app_ctx_globals_class = _AppCtxGlobals # 设置app全局对象,本质是一个字典
request_globals_class = property(_get_request_globals_class, # 设置请求上下文全局对象,其等于app_ctx_globals_class
_set_request_globals_class)
config_class = Config # 设置参数配置对象
debug = ConfigAttribute('DEBUG') # 配置文件中如果DEBUG=True就启用debug模式
testing = ConfigAttribute('TESTING') # 配置文件中如果TESTING=True就启用TESTING模式
secret_key = ConfigAttribute('SECRET_KEY') # 配置文件中如果SECRET_KEY=‘xx’就启用了密匙,默认是不启用的
# 配置文件中如果SESSION_COOKIE_NAME=‘xx’就启用了在cookie中session信息的名字,默认是session
session_cookie_name = ConfigAttribute('SESSION_COOKIE_NAME')
# 配置文件中如果PERMANENT_SESSION_LIFETIM=‘xx’就启用了session信息的失效时间,默认是31天,即一个月
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME',
get_converter=_make_timedelta)
# 设置发送文件功能最大的缓存超时时间,默认为12小时
send_file_max_age_default = ConfigAttribute('SEND_FILE_MAX_AGE_DEFAULT',
get_converter=_make_timedelta)
# 通过LOGGER_NAME指定日志对象的名称
logger_name = ConfigAttribute('LOGGER_NAME')
# 启用json格式的编解码
json_encoder = json.JSONEncoder
json_decoder = json.JSONDecoder
# 设置默认jinja模板环境
jinja_options = ImmutableDict(
extensions=['jinja2.ext.autoescape', 'jinja2.ext.with_']
)
# 常用默认的配置集合
default_config = ImmutableDict({
'DEBUG': get_debug_flag(default=False), # 默认不开启DEBUG模式
'TESTING': False, # 默认不开启TESTING模式
'SECRET_KEY': None, # 默认没有密匙
'PERMANENT_SESSION_LIFETIME': timedelta(days=31), # 默认session失效时间一个月
'USE_X_SENDFILE': False, # 不启用X_SENDFILE功能
'LOGGER_NAME': None, # 不指定logger名字,使用的是__name__
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None, # 设置服务器的名字,默认None
'SESSION_COOKIE_NAME': 'session', # 设置cookie中的session名字
'MAX_CONTENT_LENGTH': None, # 限制提交请求的最大字节数
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), # 设置文件最大缓存时间
'PREFERRED_URL_SCHEME': 'http', # 默认的通讯协议
'JSONIFY_MIMETYPE': 'application/json', # 当json数据交互时,设置响应头的mimetype参数
})
url_rule_class = Rule # 指定路由对象管理路由
session_interface = SecureCookieSessionInterface() # 指定session会话对象
def __init__(self,
import_name, # 指定app的名字
static_path=None, # 会赋值给static_url_path参数,所以一般设置static_url_path而不是这个
static_url_path=None, # 设置静态文件路由的前缀,默认为“/static”,即static_folder的路径
static_folder='static', # 指定静态文件是哪个目录
template_folder='templates',# 模板文件的存放目录,默认值为"templates"
instance_path=None, # 设置配置文件的路径,在instance_relative_config=True情况下生效
instance_relative_config=False, # 设置为True表示配置文件相对于实例路径而不是根路径
root_path=None): # app所在的根路径,默认指的是创建app这个代码的文件的目录。
# 所有定义的视图函数存放字典,以视图函数的标识符为键,视图函数对象为字典;
self.view_functions = {}
# 所有自定义的错误处理方法的存放字典,以蓝图名字为键
self.error_handler_spec = {None: self._error_handlers}
# 所有的与url错误处理方法存放列表
self.url_build_error_handlers = []
# 所有的http请求处理前的请求钩子方法存放字典
self.before_request_funcs = {}
# 第一次请求处理前的请求钩子方法存放字典
self.before_first_request_funcs = []
# 所有的http请求处理后的请求钩子方法存放字典
self.after_request_funcs = {}
# 在处理即使存在异常的情况下的请求处理后的请求钩子方法存放字典
self.teardown_request_funcs = {}
# 应用上下文被弹出之前的处理函数存放点
self.teardown_appcontext_funcs = []
# url_value_preprocessor装饰器添加,URL路径预提取
self.url_value_preprocessors = {}
# url_defaults装饰器回调添加的,在生成url时设置规则参数默认值
self.url_default_functions = {}
self.blueprints = {} # 所有的蓝图的保存字典
self.extensions = {} # 所有的flask的扩展对象的存放字典
self.url_map = Map() # 所有的Rule对象保存的字典
# 添加访问静态文件的Rule对象
if self.has_static_folder:
self.add_url_rule(self.static_url_path + '/<path:filename>',
endpoint='static',
view_func=self.send_static_file)
初始化传入相关的参数后,会执行上述代码生成一个app对象。
第二步:加载配置文件
加载配置文件有多种方式,现在只说例子中的情况:
app.config['SECRET_KEY'] = '123'
app的config对象其实是Config实例,是一个dict类型的子类,也就是说app的配置是通过一个字典来保存的,新加载的配置如果键和原来默认的配置的键相同将更新,否则添加。
class Config(dict):
pass
详细的参数配置方式参考: flask之安装和使用入门
第三步:加载蓝图
app的register_blueprint方法就是用来加载蓝图的。
app.register_blueprint(rest, url_prefix='')
# 源码
def register_blueprint(self, blueprint, **options):
......
self.blueprints[blueprint.name] = blueprint
self._blueprint_order.append(blueprint)
blueprint.register(self, options, first_registration)
如上,在app的blueprints和_blueprint_order属性中添加蓝图对象,同时蓝图调用register方法初始化。
第四步:加载请求钩子
请求钩子常用的有五种,它们通过装饰器的方式添加到app相应的存储字典中。
before_first_request:在处理第一个请求前运行。
before_request:在每次请求前运行。
after_request:如果没有未处理的异常抛出,在每次请求后运行。
teardown_request:在每次请求后运行,即使有未处理的异常抛出。
teardown_appcontext:在每次请求结束后应用上下文被弹出时执行,即appcontext调用pop方法;
@app.before_request
def test():
pass
第五步:加载视图函数
app通过route装饰器加载视图函数,将标识符和视图函数作为键值对加入app的view_functions字典属性中。
@app.route('/test3', endpoint='mytest')
def test3():
return 'ok'
route装饰器调用了app.add_url_rule(rule, endpoint, f, **options)方法,主要源码步骤为:
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
...
rule = self.url_rule_class(rule, methods=methods, **options) # 创建一个Rule对象
。。。
self.url_map.add(rule) # 在app的url_map属性即Map对象中加入rule对象
。。。
self.view_functions[endpoint] = view_func # 在app的view_functions属性中加入标识符和视图函数的键值对
第六步:加载错误处理方法
app通过errorhandler装饰器加载对应的错误或状态码相应的处理方法。
@app.errorhandler(400)
def handle_errer(errer):
print(errer)
return errer
# 其主要源码
def _register_error_handler(self, key, code_or_exception, f):
# 可以传入状态码或我们自定义的异常
exc_class, code = self._get_exc_class_and_code(code_or_exception)
handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
handlers[exc_class] = f
总结
flask框架的核心对象有:
Flask,AppContext,Map, RequestContext,Request,Response,Rule,Blueprint,session,_AppCtxGlobals;Flask主要管理着AppContext,RequestContext,以及所有的请求的处理步骤;
AppContext为应用上下文对象,主要管理app对象的获取和请求的临时状态存储变量g;
RequestContext为请求上下文,主要管理Request对象和保存会话的session对象;
Request为请求对象,在发生请求是随着RequestContext被创建而创建,管理着请求数据和Rule对象;
Response为响应对象,在应用逻辑处理完毕后创建,管理着响应数据和响应方法;
Rule路由对象,管理着路由和视图处理函数的标识符的对应关系;
Map对象管理着所有的标识符和其视图函数对象的一一对应关系;
Blueprint对象,Flask对象的缩小版,主要是为了对大量的视图函数做分类管理;
session为保存会话信息的容器,可以看做一个字典;
_AppCtxGlobals即g变量,用来在每次请求中临时存储资源,它属于应用上下文的一个属性。
参考:
flask基础之app初始化(四)的更多相关文章
- flask基础之AppContext应用上下文和RequestContext请求上下文(六)
前言 应用上下文和请求上下文存在的目的,官方文档讲的很清楚,可参考: http://www.pythondoc.com/flask/appcontext.html 应用上下文对象在没有请求的时候是可以 ...
- flask基础之请求处理核心机制(五)
前言 总结一下flask框架的请求处理流程. 系列文章 flask基础之安装和使用入门(一) flask基础之jijia2模板使用基础(二) flask基础之jijia2模板语言进阶(三) flask ...
- 【视频】零基础学Android开发:蓝牙聊天室APP(四)
零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter具体解释 4.3 ListView分布与滚动事件 4.4 ListView事件监听 ...
- Flask 基础组件(四):模板
1.模板的使用 1.1 语法 1.1.1 流程控制 逻辑语法 Jinja2模板语言中的 for {% for foo in g %} {% endfor %} Jinja2模板语言中的 if {% ...
- Flask基础全套
Flask简介 Flask是主流PythonWeb三大框架之一,其特点是短小精悍以及功能强大从而获得众多Pythoner的追捧,相比于Django它更加简单更易上手,Flask拥有非常强大的三方库,提 ...
- 狗书无敌,天下第一(flask基础)
为什么选择使用flask? 和其他框架相比, Flask 之所以能脱颖而出,原因在于它让开发者做主,使其能对程序具有全面的创意控制. 在 Flask 中,你可以自主选择程序的组件,如果找不到合适的,还 ...
- flask基础三
一.路由和视图(基础二上补充) (1)有参装饰器 路由采用的是有参装饰器实现的 @app.route("/index",methods=["GET"," ...
- flask基础入门
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- flask框架----flask基础
知识点回顾 1.flask依赖wsgi,实现wsgi的模块:wsgiref,werkzeug,uwsgi 2.实例化Flask对象,里面是有参数的 app = Flask(__name__,templ ...
随机推荐
- Qt——数据库编程
一.概述 Qt提供了一个类似JDBC的数据库接口,需要为每个可以连接的特定数据库提供驱动程序,可以通过 QStringList QSqlDatabase::drivers() 知道当前版本的Qt哪些驱 ...
- python selenium2 有关cookie操作实例及如何绕开验证码
1.先看一下cookie是啥 cookie是访问web时服务器记录在用户本地的一系列用户信息(比如用户登录信息),以便对用户进行识别 from selenium import webdriver im ...
- [BZOJ3230] 相似字串 后缀数组+RMQ
3230: 相似子串 Time Limit: 20 Sec Memory Limit: 128 MB Description Input 输入第1行,包含3个整数N,Q.Q代表询问组数.第2行是字符 ...
- BZOJ3192:[JLOI2013]删除物品——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3192 箱子再分配问题需要解决如下问题: (1)一共有N个物品,堆成M堆. (2)所有物品都是一样的 ...
- ZOJ 1081 Within(点是否在多边形内)| 计算几何
ZOJ 1081 Within 我使用的是"射线法":从该点出发,作一条向左的水平射线,与多边形的边的交点有奇数个则点在多边形内. 需要注意的点: 如果点在多边形的边上特判. 考虑 ...
- linux内核分析 第八周 理解进程调度时机跟踪分析进程调度与进程切换的过程
笔记: 实验:使用gdb跟踪分析一个schedule()函数
- 【bzoj4826】影魔
Portal --> bzoj4826 Solution 为什么莫名读了很长时间的题...== 逐渐不会语文qwq 貌似这题的做法很多,丢上来的话是因为..这个化简条件的过程莫名爽哈哈哈哈哈 注 ...
- Java虚拟机性能监控与调优
1 基于JDK命令行工具的监控 1.1 JVM的参数类型 1.1.1 标准参数 在JVM的各个版本基本上保持不变,很稳定的. -help -server -client -version -showv ...
- Matlab ------ 打开MATLAB,设置默认打开的文件夹
- 使用docker配置etcd集群
docker配置etcd集群与直接部署etcd集群在配置上并没有什么太大差别. 我这里直接使用docker-compose来实现容器化的etcd部署 环境如下: HostName IP etcd1 1 ...