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"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

项目请求流程

self.wsgi_app(environ, start_response)源码:
    def wsgi_app(self, environ, start_response):
        #ctx是ResquestContext的对象,里面request,session
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                #就是ctx放到了Local对象
                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) : environ,请求相关的,ctx现在是包含request,session的RequestContext的对象,源码

1.1 RequestContext(self, environ) self ,是app对象 environ,请求相关的

1.2 RequestContext在实例化的时候的源码:
        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._after_request_functions = []
        # 这个RequestContext对象封装了,request 和seesoin

2. ctx.push()这个ctx是RequestContext,那就执行RequestContext.push方法

2.1 RequestContext.push()的源码
    def push(self):
        #_request_ctx_stack是localStack的对象
        #self是ctx,把self也就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:
            self.match_request()
    2.1.1 _request_ctx_stack.push(self)现在的self是ctx
    2.1.2 _request_ctx_stack是LocalStack()的对象
    2.1.3 LocalStack()的push把ctx传过来
    2.1.4 LocalStack()的push方法
        源码:
        #obj是ctx
        def push(self, obj):
            #obj是ctx,requestContext的对象
            rv = getattr(self._local, "stack", None)
            if rv is None:
                # self._local是Local()的对象
                # storage[“线程id或者协程id”][stack] = [ctx,]
                self._local.stack = rv = []
            rv.append(obj)
            return rv

# 最终也就是ctx.push()他的最终目的:把当前的ctx放入到Local()里面

3. response = self.full_dispatch_request() 源码:

    def full_dispatch_request(self):
        #这是服务器第一次请求时候执行的函数
        self.try_trigger_before_first_request_functions()
        try:
            request_started.send(self)
            #执行请求之前所有的函数,并且拿到请求之前的返回值
            rv = self.preprocess_request()
            if rv is None:
                #这个是真正视图函数,如果我的请求之前函数没有返回值才会执行
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        return self.finalize_request(rv)

3.1 return self.finalize_request(rv)的源码:
    def finalize_request(self, rv, from_error_handler=False):
        response = self.make_response(rv)
        try:
            #请求之后的函数,after_request
            response = self.process_response(response)
            request_finished.send(self, response=response)
        except Exception:
            if not from_error_handler:
                raise
            self.logger.exception(
                "Request finalizing failed with an error while handling an error"
            )
        return response

4. 我们的现在已经在2步的时候把我们request已经方法Locald对象中了,我们第三步的任意一个地方都能使用我们的request,session,拿他是怎么获取的?

4.1 我们在flask导入request,这个request是一个全局的变量,我们怎么通过request区分我当前的request对象(environ),我们发现request是LocalProxy的对象
4.2 当我们用全局的request.属性的时候,就会去找LocalProxy的对象,但是我们发现里面根本就没有
    那他一定执行LocalProxy对象的__getattr__方法
4.3 我们现在来看LocalProxy对象的__getattr__方法的源码:
    #name我们要获取属性名
    def __getattr__(self, name):
        if name == "__members__":
            return dir(self._get_current_object())
        #form
        #self._get_current_object()就是ctx里面的request,
        return getattr(self._get_current_object(), name)

    4.3.1 通过反射self._get_current_object()对象,来找我们属性,也就是name
       self._get_current_object()的源码:
            def _get_current_object(self):
                if not hasattr(self.__local, "__release_local__"):
                    return self.__local()
                try:
                    #self.__local就实例化传过来的偏函数,
                    return getattr(self.__local, self.__name__)
                except AttributeError:
                    raise RuntimeError("no object bound to %s" % self.__name__)

       4.3.1.1 return getattr(self.__local, self.__name__)那这里self.__local是谁?
                def __init__(self, local, name=None):
                      object.__setattr__(self, "_LocalProxy__local", local)
                self.___local为local
                这个local为实例化的时候传的

            4.3.1.1.1 这个实例化的时候的操作
               request = LocalProxy(partial(_lookup_req_object, "request"))
               4.3.1.1的local就是 partial(_lookup_req_object, "request")的地址

            4.3.1.1.2 _lookup_req_object的源码:
                #调用的时候 partial(_lookup_req_object, "request")
                #现在的name就是"request"
                def _lookup_req_object(name):
                    # top是当前线程的ctx
                    top = _request_ctx_stack.top
                    if top is None:
                        raise RuntimeError(_request_ctx_err_msg)
                    #找top里面的request
                    # ctx找request
                    return getattr(top, name)
            4.3.1.1.3 我们来看这个_request_ctx_stack.top的top方法
                    def top(self):
                        try:
                            return self._local.stack[-1]
                        except (AttributeError, IndexError):
                            return None
                    # 我们发现这个self._local是Local()对象,这样就把ctx拿到了

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

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

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

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_dispat

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模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器. “微”