zoukankan      html  css  js  c++  java
  • flask的源码之请求

    请求上下文

    golbal文件,生成这些对象

    _request_ctx_stack = LocalStack()
    _app_ctx_stack = LocalStack()
    current_app = LocalProxy(_find_app)
    request = LocalProxy(partial(_lookup_req_object, "request"))
    session = LocalProxy(partial(_lookup_req_object, "session"))
    

    每一次有请求都会执行app.wsig_app(environ, start_response)

    app.wsig_app源码:

        def wsgi_app(self, environ, start_response):
            # RequestContext的对象,其中包含当前请求的东西。
            ctx = self.request_context(environ)
            error = None
            try:
                try:
                    #RequestContext的对象,ctx.push,就执行是RequestContext对象的push方法
                    #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)
    

    ctx = self.request_context(environ)做了什么?ctx=RequestContext的对象,里面有请求相关等所有东西:

    # 1 我们self.request_context(environ)执行是:所以ctx是RequestContext(self, environ)的返回值:
    	    def request_context(self, environ):
                #等一下返回的ctx就是RequestContext()执行的结果。
                return RequestContext(self, environ)
    #2 RequestContext(self, environ)的执行结果是什么?是RequestContext的对象,这个对象中包含了reuqest等信息
    class RequestContext(object):
        #app, environ,ctx,就是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
    
    



    ctx.push(),这里的ctx,是RequestContext的对象,

    #1 ctx.push方法就执行RequestContext的对象的push方法:
    #源码:
        def push(self):
            #当前的self是RequestContext的对象,也就是ctx,
            _request_ctx_stack.push(self)
    #2  _request_ctx_stack,我们发现它是全局LocalStack()的对象。
    #_request_ctx_stack.push(self)就是执行LocalStack中的push方法,并且把ctx传给了#_request_ctx_stack.push的push方法。self=ctx
    #LocalStack中的push源码:
      
        def push(self, obj):
            rv = getattr(self._local, "stack", None)
            if rv is None:
                #storage[线程,协程id]["stack"] = []
                self._local.stack = rv = []
            rv.append(obj)
            return rv
        
    #上述代码中的self._local是Local对象,用来保证数据安全。
    #当代码执行self._local.stack = rv = [],再Local对象中的存储结构是:storage[线程,协程id]["stack"] = []
    # rv.append(obj),把storage[线程,协程id]["stack"] = [obj],又由于obj=ctx,就算就是把ctx放入到Local对象中。结构如下Local().storage[线程,协程id]["stack"] = [ctx]
    







    response = self.full_dispatch_request()

    #1
    #这句话我们执行是请扩展与响应函数
    #再响应函数和请求扩展中就可以使用request,它是如果和实现的呢?
    from flask import Flask,request,session
    app = Flask(__name__)
    def index():
        print(request.method)
        print(session)
        return  "ok"
    #比如上面代码中request.method,是如何拿到请求相关的内容呢?
    
    
    #2
    
    #我们点进去看request是什么?
    request = LocalProxy(partial(_lookup_req_object, "request"))
    #我们发现request就是 LocalProxy的对象。
    #那我们再LocalProxy应该能找到method属性,但是发现没有,既然没有,它就一定写了__getattr__
    #我们看__getattr__的源码:
     def __getattr__(self, name):
            #request.method,现在的name就是method
            if name == "__members__":
                return dir(self._get_current_object())
            #现在的name是method,self._get_current_object()执行结果就偏函数的执行结果
            #偏函数的执行结果中来获取method
            #偏函数的执行结果就是request.
            #etattr(request, method)
            return getattr(self._get_current_object(), name)
        
        
        
    #3     
    #我们再看看_get_current_object()它的执行结果是什么?
    #self._get_current_object()的源码:
        def _get_current_object(self):
                return self.__local()       
    #上面的self._get_current_object()执行结果就是self.__local()的执行结果
    
    
    # 4 
    #self.__local是什么?
    #我们发现这个self.__local是实例化的时候传递的,也就local,代码如下
     def __init__(self, local, name=None):
            #self.__local= _LocalProxy__local=local = partial(_lookup_req_object, "request")
            #self.__local设置为隐藏属性,
            object.__setattr__(self, "_LocalProxy__local", local)
           # self.__local=local
        
    #local是实例化的时候传递的。我们实例化这个 LocalProxy(partial(_lookup_req_object, "request"))
    # 我们self._get_current_object=self.__local=local=partial(_lookup_req_object, "request")
    
    #5
    #那最终我们明白了:
    def __getattr__(self, name):
            #request.method,现在的name就是method
            if name == "__members__":
                return dir(self._get_current_object())
            return getattr(self._get_current_object(), name)
        
    #self._get_current_object() 执行结果,就partial(_lookup_req_object, "request")的执行结果。
    #就是ctx.request,所以getattr(self._get_current_object(), name)相当于getattr(ctx.request, method)
    
    #6 
    #partial(_lookup_req_object, "request")()执行的结果
    #_lookup_req_object的代码如下:
    
    def _lookup_req_object(name):
    	#这里的name,是"request"
        top = _request_ctx_stack.top
      
        #top是谁?是ctx.
        if top is None:
            raise RuntimeError(_request_ctx_err_msg)
        #top里面找request,也就是top= ctx--》ctx里面找request.
        return getattr(top, name)
    
    # 7 
    #又因为_request_ctx_stack是LocalStack()的对象,所以 _request_ctx_stack.top就是执行LocalStack()的对象中的top:
    #_request_ctx_stack.top的源码:
        @property
        def top(self):
            try:
                # storage[线程,协程id]["stack"] = [ctx]
                #现在top的retrun值就ctx
                return self._local.stack[-1]
            except (AttributeError, IndexError):
                return None
    #代码中的self._local是Local对象,是我们存ctx的时候的Local对象。        
    
    









  • 相关阅读:
    win7-64系统下安装nodejs
    Vue项目使用npm run dev出现npm ERR! missing script: dev
    本地环境时覆盖Apollo配置
    金蝶K3序时簿页面增加物料即时库存显示功能
    LeetCode——开篇
    url 与 params 参数的常见操作归纳汇总(含精心准备的注释)
    如何让 arcgis require 里定义的方法可以在全局访问?
    字体图标库 iconfont、iconmoon 的维护管理与使用探索
    【转载】ES5-ES12 常用语法特性
    一次 outline 去除经验(非继承属性,看着像继承)
  • 原文地址:https://www.cnblogs.com/yafeng666/p/12535461.html
Copyright © 2011-2022 走看看