07 flask源码剖析之用户请求过来流程
07 Flask源码之:用户请求过来流程
1.创建ctx = RequestContext对象
RequestContext对象封装Request对象
RequestContext对象封装session数据
源码实现:
def wsgi_app(self, environ, start_response):
"""
ctx = RequestContext(self, environ)
"""
# 2.1 创建RequestContext对象
ctx = self.request_context(environ)
def request_context(self, environ):
return RequestContext(self, environ)
request_class = Request class RequestContext(object):
def __init__(self, app, environ, request=None, session=None):
self.app = app
if request is None:
"""
request_class = Request
"""
request = app.request_class(environ)
self.request = request
self.session = session
2. 创建app_ctx = AppContext对象
AppContext对象封装App对象
AppContext对象封装g
源码实现:
def wsgi_app(self, environ, start_response):
"""
ctx = RequestContext(self, environ)
"""
# 2.1 创建RequestContext对象
ctx = self.request_context(environ)
error = None
try:
try:
"""
2.2 执行ctx.push
- app_ctx = 创建AppContext对象(app,g)
- 将app_ctx放入local中
- 将ctx放入到local中
- session赋值
- 路由匹配
"""
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 = AppContext(app)
"""
# 创建appcontext对象
app_ctx = self.app.app_context()
def app_context(self):
return AppContext(self)
class AppContext(object):
def __init__(self, app):
self.app = app
self.g = app.app_ctx_globals_class()
3. 将ctx对象、app_ctx对象放到local中
然后ctx.push触发将 ctx对象,通过自己的LocalStack对象将其放入到Local中
然后app_ctx.push触发将 app_ctx对象,通过自己的LocalStack对象将其放入到Local中
Local的本质是以线程ID为key,以{“stack”:[]}为value的字典
存储结构:{
1111:{“stack”:[ctx,]}
}; {
1111:{“stack”:[app_ctx,]}
}源码示例:
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 = AppContext(app)
"""
# 创建appcontext对象
app_ctx = self.app.app_context()
# push将app_ctx放入到local中
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()
"""
self = ctx = RequestContext(self, environ)
"""
# push将ctx放入到local中
_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:
# 路由匹配,将匹配到的endpoint放到request.url_rule中
self.match_request()
4. 执行所有before_request函数以及所有的视图函数
- 执行full_dispatch_request函数
- 执行所有的before_request函数
- 执行视图函数
源码示例:
def wsgi_app(self, environ, start_response):
"""
ctx = RequestContext(self, environ)
"""
#2.1 创建RequestContext对象
ctx = self.request_context(environ)
error = None
try:
try:
# 做了很多事
"""
2.2 执行ctx.push
- app_ctx = 创建AppContext对象(app,g)
- 将app_ctx放入local中
- 将ctx放入到local中
- session赋值
- 路由匹配
"""
ctx.push()
# 2.3 执行before_request/视图/after_request (处理session)
response = self.full_dispatch_request()
def full_dispatch_request(self):
# 触发所有的before_first_request_funcs函数
# 只在启动程序后,第一个请求到来时执行
self.try_trigger_before_first_request_functions()
try:
# 信号,暂留
request_started.send(self)
# 执行before_request_funcs函数,如果有返回值就不执行视图函数了
rv = self.preprocess_request()
if rv is None:
# 执行视图函数
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
# 视图函数执行之后
# 1.执行所有的after_request
# 2.保存session
return self.finalize_request(rv)
5. 执行所有after_request函数
session会加密返回给用户浏览器放到cookie中
源码示例:
def finalize_request(self, rv, from_error_handler=False):
# 将rv视图函数返回值,封装到Reponse对象中
response = self.make_response(rv)
response = self.process_response(response)
return response
response_class = Response def make_response(self, rv):
if not isinstance(rv, self.response_class):
if isinstance(rv, (text_type, bytes, bytearray)):
rv = self.response_class(rv, status=status, headers=headers)
return rv
def process_response(self, response):
ctx = _request_ctx_stack.top
funcs = ctx._after_request_functions
# 执行所有的after_request_funcs
funcs = chain(funcs, reversed(self.after_request_funcs[None]))
for handler in funcs:
response = handler(response)
if not self.session_interface.is_null_session(ctx.session):
# 保存session
self.session_interface.save_session(self, ctx.session, response)
return response
6. 销毁ctx和app_ctx
如果请求结束不销毁ctx和app_ctx的话,会造成内存泄漏
分别调用ctx和app_ctx的pop方法
源码示例:
def wsgi_app(self, environ, start_response):
"""
ctx = RequestContext(self, environ)
"""
#2.1 创建RequestContext对象
ctx = self.request_context(environ)
error = None
try:
try:
"""
2.2 执行ctx.push
- app_ctx = 创建AppContext对象(app,g)
- 将app_ctx放入local中
- 将ctx放入到local中
- session赋值
- 路由匹配
"""
ctx.push()
# 2.3 执行before_request/视图/after_request (处理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)def auto_pop(self, exc):
self.pop(exc)
def pop(self, exc=_sentinel):
app_ctx = self._implicit_app_ctx_stack.pop()
finally:
rv = _request_ctx_stack.pop()
if app_ctx is not None:
app_ctx.pop(exc)
07 flask源码剖析之用户请求过来流程的更多相关文章
- flask源码剖析系列(系列目录)
flask源码剖析系列(系列目录) 01 flask源码剖析之werkzurg 了解wsgi 02 flask源码剖析之flask快速使用 03 flask源码剖析之threading.local和高 ...
- 07 drf源码剖析之节流
07 drf源码剖析之节流 目录 07 drf源码剖析之节流 1. 节流简述 2. 节流使用 3. 源码剖析 总结: 1. 节流简述 节流类似于权限,它确定是否应授权请求.节流指示临时状态,并用于控制 ...
- 08 Flask源码剖析之flask拓展点
08 Flask源码剖析之flask拓展点 1. 信号(源码) 信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作. pip3 install blinker 2. 根据flas ...
- Apache DolphinScheduler 源码剖析之 Worker 容错处理流程
今天给大家带来的分享是 Apache DolphinScheduler 源码剖析之 Worker 容错处理流程 DolphinScheduler源码剖析之Worker容错处理流程 Worker容错流程 ...
- DolphinScheduler 源码剖析之 Master 容错处理流程
点击上方蓝字关注 Apache DolphinScheduler Apache DolphinScheduler(incubating),简称"DS", 中文名 "海豚调 ...
- Flask源码剖析详解
1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识.从而 ...
- 04 flask源码剖析之LocalStack和Local对象实现栈的管理
04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...
- 06 flask源码剖析之路由加载
06 Flask源码之:路由加载 目录 06 Flask源码之:路由加载 1.示例代码 2.路由加载源码分析 1.示例代码 from flask import Flask app = Flask(__ ...
- flask 源码剖析
flask 上下文管理源码流程及涉及的部分技术点 [flask源码梳理]之一 偏函数_mro [flask源码梳理]之二 面向对象中__setattr__ [flask源码梳理]之三 Local ...
随机推荐
- kafka架构、基本术语、消息存储结构
1.kafka架构 kafka处理消息大概流程 生产者发送消息给kafka服务器 消费者从kafka服务器(broker)读取消息 kafka服务器依靠zookeeper集群进行服务协调管理 2.ka ...
- TensorFlow从0到1之XLA加速线性代数编译器(9)
加速线性代数器(Accelerated linear algebra,XLA)是线性代数领域的专用编译器.根据 https://www.tensorflow.org/performance/xla/, ...
- centos7 hadoop 单机模式安装配置
前言 由于现在要用spark,而学习spark会和hdfs和hive打交道,之前在公司服务器配的分布式集群,离开公司之后,自己就不能用了,后来用ambari搭的三台虚拟机的集群太卡了,所以就上网查了一 ...
- loadrunner常见问题及解决办法
LoadRunner录制脚本时不弹出IE浏览器解决方法:启动浏览器,打开Internet选项对话框,切换到高级标签,去掉"启用第三方浏览器扩展(需要重启动)"的勾选,然后再次运行V ...
- rust 九九乘法表
fn main(){ for i in 1..10 { for j in 1..i+1 { print!("{}*{}={:<2} ",j,i,i*j); } print!( ...
- 常见CSS选择器的权重和优先级
一.常见CSS选择器 [元素选择器] 1.通配选择器:*(匹配所有元素) a.效率不高,页面上的标签越多,效率越低,所以页面上最好不要出现这个选择器 2.标签选择器:li(匹配标签为li的元素) a. ...
- JAVA设计模式 1 设计模式介绍、单例模式的理解与使用
数据结构我们已经学了一部分了.是该了解了解设计模式了.习惯了CRUD的你,也该了解了解这一门神器.我为啥要说是神器呢? 因为在大厂的面试环节.以及很多的比如 Springboot Mybatis 等开 ...
- CPU明明8个核,网卡为啥拼命折腾一号核?
中断机制 我是CPU一号车间的阿Q,我又来了! 我们日常的工作就是不断执行代码指令,不过这看似简单的工作背后其实也并不轻松. 咱不能闷着头啥也不管一个劲的只管执行代码,还得和连接在主板上的其他单位打交 ...
- 他被称为"中国第一程序员",微软得不到他曾想毁了他,如今拜入武当修道
GitHub 15.4k Star 的Java工程师成神之路,不来了解一下吗! GitHub 15.4k Star 的Java工程师成神之路,真的不来了解一下吗! GitHub 15.4k Star ...
- 专家解读:利用Angular项目与数据库融合实例
摘要:面对如何在现有的低版本的框架服务上,运行新版本的前端服务问题,华为云前端推出了一种融合方案,该方案能让独立的Angular项目整体运行在低版本的框架服务上,通过各种适配手段,让Angular项目 ...