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. Memory layout

    Text Segment       Text Segment,通常也被称为代码段. 为了防止 heap 或是 stack 的溢出,text 段常被安排在 heap 或是 stack 之后. Text ...

  2. Python删除一个列表元素的方法

    参考资料: https://www.cnblogs.com/xiaodai0/p/10564956.html https://www.cnblogs.com/huangbiquan/articles/ ...

  3. ubuntu启动打开终端快捷键

    ubuntu启动打开终端快捷键 CTRL+ALT+T

  4. ASP.NET处理管道之防盗链

    盗链就是在用户向网站a请求网站资源时,网站a将网站资源的路径填写为b网站资源的地址,用户将直接看到网站a上显示着网站b的资源,从而造成盗链. 要防止盗链,就要用到处理管道中的技术 在相应的模块类中: ...

  5. Lucene5多条件查询

    lucene是一个很强大的搜索工具,最近公司项目上用到,结合JAVA1234所讲,对多条件查询做出总结 先描述一下我的多条件需求,如果和您的类似,继续往下看. 1.我的Lucene搜索会在很多地方使用 ...

  6. 第一章:开始启程-你的第一行Android代码

    Android 系统为开发者提供了什么? 四大组件 活动(Activity):界面 服务(Service):后台默默运行 广播接收器(Broadcast Receiver):接收.发送广播消息 内容提 ...

  7. AbstractQueuedSynchronizer和ReentranLock基本原理

    先把我主要学习参考的文章放上来先,这篇文章讲的挺好的,分析比较到位,最好是先看完这篇文章,在接下去看我写的.不然你会一脸懵逼,不过等你看完这篇文章,可能我的文章对你也用途不大了 深入分析Abstrac ...

  8. 线性dp 打鼹鼠

    鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个n*n 的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气.你可以控 ...

  9. Salesforce LWC学习(十八) datatable展示 image

    本篇参看: https://developer.salesforce.com/docs/component-library/bundle/lightning-datatable/documentati ...

  10. python+opencv实现检测物体聚集区域

    内容涉及:二值图像转换 / 检测连通区域面积 / 在原图上画框等 import cv2 import numpy as np for n in open('list.txt'): # list.txt ...