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. Github上可以涨薪30k的Java教程和实战项目终于可以免费下载了

    写在前面 大家都知道 Github 是一个程序员福地,这里有各种厉害的开源框架.软件或者教程.这些东西对于我们学习和进步有着莫大的进步,所以我有了这个将 Github 上非常棒的 Java 开源项目整 ...

  2. blob斑点检测

    目录 1. 可选算法 1.1. Laplacian of Gaussian (LoG) 1.2. Difference of Gaussian (DoG) 1.3. Determinant of He ...

  3. [转] C++中的namespace

    点击阅读原文 namespace中文意思是命名空间或者叫名字空间,传统的C++只有一个全局的namespace,但是由于现在的程序的规模越来越大,程序的分工越来越细,全局作用域变得越来越拥挤,每个人都 ...

  4. JavaScript 定时器 取消定时器

    感谢:链接(视频讲解很清晰) 定时器:作用主要是一定时间间隔后,做出相关的变化,例如图片轮播. 目录 两种定时器的使用 两种定时器区别 取消定时器的方法 两种定时器的使用: 方法一:setTimeou ...

  5. PyQt5 FileDialog的使用例子

    加载***.ui文件可以使用: loadUi('main_window.ui', self) self.btnFileChoose.clicked.connect(self.getFolderName ...

  6. foreach 集合又抛经典异常了,这次一定要刨根问底

    一:背景 1. 讲故事 最近同事在写一段业务逻辑的时候,程序跑起来总是报:集合已修改:可能无法执行枚举操作,硬是没有找到什么情况下会导致这个异常产生,就让我来找一下bug,其实这个异常在座的每个程序员 ...

  7. STL sort的comp函数注意事项

    今天写了个题,结果碰巧re了,我眉头一皱发现事情并不简单. 原来我之前的comp写的都是错的. bool cmp(milkman a,milkman b) { return a.price<=b ...

  8. WeChair项目Alpha冲刺(4/10)

    团队项目进行情况 1.昨日进展    Alpha冲刺第四天 昨日进展: 前端完成小程序登录态的定义 LoginController编写初步完成同时修改并更新了代码,但是在将编码好的项目部署到服务器上时 ...

  9. Latex文件本机能正常编译,但在另一台电脑不能编译的解决方法

    问题:同样的文件在台式机能编译出正常的PDF文件,但发现在另一个电脑上不能编译出PDF文件. \documentclass[preprint,10pt,5p,times,twocolumn]{elsa ...

  10. 网易java高级开发课程 面对上亿数据量,网易用啥技术?