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函数以及所有的视图函数

  1. 执行full_dispatch_request函数
  2. 执行所有的before_request函数
  3. 执行视图函数
  • 源码示例:

    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源码剖析之用户请求过来流程的更多相关文章

  1. flask源码剖析系列(系列目录)

    flask源码剖析系列(系列目录) 01 flask源码剖析之werkzurg 了解wsgi 02 flask源码剖析之flask快速使用 03 flask源码剖析之threading.local和高 ...

  2. 07 drf源码剖析之节流

    07 drf源码剖析之节流 目录 07 drf源码剖析之节流 1. 节流简述 2. 节流使用 3. 源码剖析 总结: 1. 节流简述 节流类似于权限,它确定是否应授权请求.节流指示临时状态,并用于控制 ...

  3. 08 Flask源码剖析之flask拓展点

    08 Flask源码剖析之flask拓展点 1. 信号(源码) 信号,是在flask框架中为我们预留的钩子,让我们可以进行一些自定义操作. pip3 install blinker 2. 根据flas ...

  4. Apache DolphinScheduler 源码剖析之 Worker 容错处理流程

    今天给大家带来的分享是 Apache DolphinScheduler 源码剖析之 Worker 容错处理流程 DolphinScheduler源码剖析之Worker容错处理流程 Worker容错流程 ...

  5. DolphinScheduler 源码剖析之 Master 容错处理流程

    点击上方蓝字关注 Apache DolphinScheduler Apache DolphinScheduler(incubating),简称"DS", 中文名 "海豚调 ...

  6. Flask源码剖析详解

    1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识.从而 ...

  7. 04 flask源码剖析之LocalStack和Local对象实现栈的管理

    04 LocalStack和Local对象实现栈的管理 目录 04 LocalStack和Local对象实现栈的管理 1.源码入口 1. flask源码关于local的实现 2. flask源码关于l ...

  8. 06 flask源码剖析之路由加载

    06 Flask源码之:路由加载 目录 06 Flask源码之:路由加载 1.示例代码 2.路由加载源码分析 1.示例代码 from flask import Flask app = Flask(__ ...

  9. flask 源码剖析

    flask 上下文管理源码流程及涉及的部分技术点 [flask源码梳理]之一  偏函数_mro [flask源码梳理]之二  面向对象中__setattr__ [flask源码梳理]之三  Local ...

随机推荐

  1. SpringMVC中的@RequestMapping注解

    @RequestMapping:设置请求映射,把请求和控制层中的方法设置映射关系 属性: 当请求路径和@RequestMapping的value属性一致时,则该注解所标注的方法即为处理请求的方法 me ...

  2. 包子凑数(dp 0-1、完全背包)【背包问题】

    包子凑数(蓝桥杯) 感谢:@ Statusrank 题目链接(点击) 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐.他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子.每种蒸笼都有非常多 ...

  3. 【JMeter_12】JMeter逻辑控制器__包括控制器<Include Controller>

    包括控制器<Include Controller> 业务逻辑: 通过Filename的路径和文件名引用外部的jmx文件,然后对齐执行,若外部文件中没有可执行范围内的脚本内容,则跳过该逻辑控 ...

  4. leetcode27之移除元素

    题目描述: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改 ...

  5. Netty的Marshalling编解码器

    1.编码与解码    通常我们习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途.反之,解码(Decode)称为反序列化 ...

  6. Redis持久性——RDB和AOF

    Redis持久性 Redis提供了不同的持久性选项: RDB持久性以指定的时间间隔执行数据集的时间点快照. AOF持久性记录服务器接收的每个写入操作,将在服务器启动时再次播放,重建原始数据集.使用与R ...

  7. JavaWeb网上图书商城完整项目--24.注册页面的css样式实现

    现在框架已经做好了,即下来我们要对页面进行装饰了,第一步给每一个元素添加id 1.最外面的div添加id为divMain 2.第二个div添加id为divTitle,里面的span对应的id为span ...

  8. java scoket Blocking 阻塞IO socket通信三

    在NIO同步非阻塞的场景中和原来同步阻塞最大的却别就是引入了上面的Buffer对象,现在我们来学校上面的BUffer对象 我们来看看程序的代码: package bhz.nio.test; impor ...

  9. 微信小程序 自定义省市选择器

    1.把省市数据放在city.js中,city.js放在until目录下 // city.js module.exports = { "province": [ { "ti ...

  10. 对于python 作用域新的理解

    今天看Python习题,看到如下题目 def num(): return [lambda x: i*x for i in range(4)] print([m(2) for m in num()]) ...