Flask快速入门(13) — 请求上下文1

目录

  • 1. ctx=self.request_context(environ)
  • 2. ctx.push()
    • 2.1 _request_ctx_stack是什么?
  • 3. response = self.full_dispatch_request()
  • 4. ctx.auto_pop(error)
    • 4.1 rv =_request_ctx_stack.pop()

之前分析了flask项目从启动到请求结束实际是执行了wsgi_app函数,在“请求流程”中也分析了self.full_dispatch_request()是执行了请求的视图函数以及请求扩展。现在分析其它源码:

def wsgi_app(self, environ, start_response):
    ctx = self.request_context(environ)
    error = None
    try:
        try:
            ctx.push()
            # 执行了请求的视图函数以及请求扩展
            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
        ctx.auto_pop(error)

1. ctx=self.request_context(environ)

def request_context(self, environ):
    return RequestContext(self, environ)

def __init__(self, app, environ, request=None, session=None):
    self.app = app
    if request is None:
        request = app.request_class(environ)
    self.request = request
    self.url_adapter = None
    try:
        self.url_adapter = app.create_url_adapter(self.request)
    except HTTPException as e:
        self.request.routing_exception = e
    self.flashes = None
    self.session = session
    self._implicit_app_ctx_stack = []
    self.preserved = False
    self._preserved_exc = None
    self._after_request_functions = []

ctx 就是RequestContext的一个对象,封装了一些参数,包括处理后的request、session...

2. ctx.push()

ctx是RequestContext对象,实际是执行了RequestContext的push方法,在push方法里主要看执行了_request_ctx_stack.push(self)方法

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 = self.app.app_context()
        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()

    _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:
        self.match_request()

2.1 _request_ctx_stack是什么?

_request_ctx_stack是LocalSrack()的对象,也就是说_request_ctx_stack.push(self)执行的是LocalSrack的push方法,self就是ctx(请求相关的)

def push(self, obj):
    # 从self._local获取"stack"值,若为None,就设为空列表[];否则将obj即ctx放入“stack”的列表中去
    rv = getattr(self._local, "stack", None)
    if rv is None:
        self._local.stack = rv = []
    rv.append(obj)
    return rv

self._local就是local对象。local中没有stack属性,所以执行local的__getattr__()方法。这就是flask上篇介绍到的local对象。通过线程id或协程id来开辟不同的存储空间,放入request、session等相关的信息。这样就可以实现多线程或多协程

3. response = self.full_dispatch_request()

请看“请求流程“篇,这里不再重复介绍

4. ctx.auto_pop(error)

def auto_pop(self, exc):
    if self.request.environ.get("flask._preserve_context") or (
        exc is not None and self.app.preserve_context_on_exception
    ):
        self.preserved = True
        self._preserved_exc = exc
    else:
        self.pop(exc)  # self是ctx,所以执行的是RequestContext的pop方法

def pop(self, exc=_sentinel):
    app_ctx = self._implicit_app_ctx_stack.pop() # self._implicit_app_ctx_stack = []
    try:
        clear_request = False
        if not self._implicit_app_ctx_stack:
            self.preserved = False
            self._preserved_exc = None
            if exc is _sentinel:
               exc = sys.exc_info()[1]
            self.app.do_teardown_request(exc)
            if hasattr(sys, "exc_clear"):
                sys.exc_clear()
            request_close = getattr(self.request, "close", None)  # 如果有request.close就执行request_close()方法
            if request_close is not None:
                request_close()
            clear_request = True
    finally:
        rv = _request_ctx_stack.pop()  # 主要是执行了这句
        if clear_request:
            rv.request.environ["werkzeug.request"] = None
        if app_ctx is not None:
            app_ctx.pop(exc)
        assert rv is self, "Popped wrong request context. (%r instead of %r)" % (rv,self,)

4.1 rv =_request_ctx_stack.pop()

刚刚提到过_request_ctx_stack是LocalStack对象,所以执行的是LocalStack的pop方法

def pop(self):
    # self._local是Local对象,获取stack属性值,如果有就return stack[-1]
    stack = getattr(self._local, "stack", None)
    if stack is None:
        return None
    elif len(stack) == 1:
        release_local(self._local)
        return stack[-1]
    else:
        return stack.pop()

总结:在该请求执行完之后pop掉ctx请求

原文地址:https://www.cnblogs.com/863652104kai/p/11704813.html

时间: 2024-10-08 17:32:52

Flask快速入门(13) — 请求上下文1的相关文章

Flask快速入门(15) — 请求上下文总结

目录 全局的变量 项目请求流程 全局的变量 _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) #local就是我们的partial(_lookup_req_object, "request") request = LocalProxy(partial(_lookup_req_object, "request")) se

Flask快速入门(11) — 请求流程

目录 full_dispatch_request() flask项目整个请求流程其实就是执行:wsgi_app()方法中调用的full_dispatch_request(),包括请求扩展和真正的视图函数 full_dispatch_request() def full_dispatch_request(self): # 执行before_first_request函数 self.try_trigger_before_first_request_functions() try: # 发送请求开始信

Flask快速入门(18) — 信号

Flask快速入门(18) - 信号 作用:Flask框架中的信号基于blinker,其主要就是让开发者可以在flask请求过程中定制一些用户行为 安装:pip install blinker 内置信号: request_started = _signals.signal('request-started') # 请求到来前执行 request_finished = _signals.signal('request-finished') # 请求结束后执行 before_render_templ

网站后端_Python+Flask.0003.FLASK快速入门之Hello Word?

框架特点: 1. 非常小, 小到可称为微型框架 2. 可扩展, 设计初衷就是不会替开发者做太多决策,支持随时更换或动手实现扩展模块 3. 三依赖, 路由/调试/WSGI(由WERKZEUG提供的WEB服务器网关接口实现),模版系统(由JINJA2实现),签名(由ITSDANGEROUS实现) 快速安装: pip install flask 快速入门: #!/usr/bin/env python # -*- coding: utf-8 -*- """ # # Authors: 

Flask快速入门(17) — flask_session

Flask快速入门(17) - flask_session 作用:将默认保存的签名cookie中的值,保存到 redis/memcached/file/Mongodb/SQLAlchemy 安装:pip install flask-session 使用1: from flask import Flask,session from flask_session import RedisSessionInterface import redis app = Flask(__name__) conn=r

Flask快速入门(20) — 多app应用

Flask快速入门(20) - 多app应用 之前一直是一个app,如果有多个app该怎么进行分发呢? from werkzeug.wsgi import DispatcherMiddleware from werkzeug.serving import run_simple from flask import Flask,current_app # 注册两个app app1 = Flask('app01') app2 = Flask('app02') @app1.route('/index')

【转】Flask快速入门

迫不及待要开始了吗?本页提供了一个很好的 Flask 介绍,并假定你已经安装好了 Flask.如果没有,请跳转到 安装 章节. 一个最小的应用 一个最小的 Flask 应用看起来会是这样: from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() 把它保存为 hello.py 

flask快速入门笔记三_上下文对象:Flask核心机制

首先声明:内容大部分来自huizhiwang,只是单纯记笔记. 1 请求 :WSGI WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的Web服务器和Web应用程序之间的一种简单而通用的接口. WSGI将Web服务分成两个部分:服务器和应用程序.WGSI服务器只负责与网络相关的两件事:接收浏览器的 HTTP请求.向浏览器发送HTTP应答:而对HTTP请求的具体处理

Flask快速入门,知识整理

一.Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来) Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器. “微”