• day93 请求上文文总结分析


    请求上下文总结分析

    from flask import Flask
    
    app = Flask(__name__)
    
    if __name__ == '__main__':
        app.__call__
        app.run()
    
    '''
    整个flask的源码:
        def wsgi_app(self, environ, start_response):
            # ctx就是 RequestContext的一个对象 里面包含了请求相关的所有东西
            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)---》ctx本质是RequestContext的对象
        1.1 RequestContext(self, environ):self是当前的app,environ是请求相关的
        1.2 RequestContext(self, environ)执行的结果是RequestContext类的对象,该对象中包含了请求相关和当前app
        1.3 所以这个ctx就是RequestContext的对象
         
    2 ctx.push():当前ctx是RequestContext的对象,那就是执行RequestContext对象的push方法
        2.1 ctx.push方法中有一个_request_ctx_stack.push(self);这个self是ctx,那就是把ctx传递个_request_ctx_stack
        
        2.2 _request_ctx_stack就是LocalStack的对象
        
        2.3 _request_ctx_stack.push  
        源码如下:
            #obj就是_request_ctx_stack.push(self)传过来的self,也就是ctx
            def push(self, obj):
                rv = getattr(self._local, "stack", None)
                if rv is None:
                    #_local=local -->setattr
                    # storage[线程/协程id][stack] = []
                    self._local.stack = rv = []
                # storage[线程/协程id][stack] = [obj,]
                rv.append(obj)
                return rv
                
            2.3.1 在2.3的代码中self._local.stack做的事情
                发现self._local是Local对象,所以self._local就执行了Local对象的__setattr__:
                代码如下:
                    def __setattr__(self, name, value):
                        ident = self.__ident_func__()
                        storage = self.__storage__
                        try:
                            storage[ident][name] = value
                        except KeyError:
                            storage[ident] = {name: value}
        总结:
            就是将ctx放到Local对象以storage[ident][stack] = [ctx,]的形式存储
    
    
    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 self.try_trigger_before_first_request_functions()
        这是在请求扩展中的before_first_request
        他是如何判断项目启动后只执行一次里面的方法:
            通过self._got_first_request变量来判断的,初始值为False,一旦执行过了该函数,在函数的末尾将self._got_first_request设置成True
        源码如下:
            def try_trigger_before_first_request_functions(self):
                if self._got_first_request:
                    return
                with self._before_request_lock:
                    if self._got_first_request:
                        return
                    #这里去循环第一次执行的函数,请求扩展的里面
                    for func in self.before_first_request_funcs:
                        func()
                    self._got_first_request = True
                    
        3.2 rv = self.preprocess_request() 这里执行的是befor_request的函数
        源码如下:
            def preprocess_request(self):
                bp = _request_ctx_stack.top.request.blueprint
                
                funcs = self.url_value_preprocessors.get(None, ())
                if bp is not None and bp in self.url_value_preprocessors:
                    funcs = chain(funcs, self.url_value_preprocessors[bp])
                for func in funcs:
                    func(request.endpoint, request.view_args)
                # 请求之前要做的事情,请求之前的请求扩展
                funcs = self.before_request_funcs.get(None, ())
                if bp is not None and bp in self.before_request_funcs:
                    funcs = chain(funcs, self.before_request_funcs[bp])
                for func in funcs:
                    rv = func()
                    if rv is not None:
                        return rv
                        
            3.2.1 funcs = self.before_request_funcs.get(None, ())这里是获取所有注册进来的befor_request
            
            3.2.2 下面的代码可以看出:如果befor_request函数有一个返回值,那么后面的函数都不执行,并且把返回值给rv = self.preprocess_request()里的rv
                for func in funcs:
                    rv = func()
                    if rv is not None:
                        return rv
                        
        3.3 if rv is None: #这个rv是3.2中before_request返回的,如果没有返回值,才会执行rv = self.dispatch_request(),有返回值就不会执行
                    rv = self.dispatch_request()#这个是真正的响应函数
            通过这个代码:知道如果before_request有返回值,就不会执行真正的响应函数
            
        3.4 return self.finalize_request(rv):这个rv是3.2或3.3的返回值
        源码如下:
            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
                
            3.4.1 response = self.process_response(response):这里做after_request请求扩展的
            源码如下:
                def process_response(self, response):
                    ctx = _request_ctx_stack.top
                    bp = ctx.request.blueprint
                    funcs = ctx._after_request_functions
                    if bp is not None and bp in self.after_request_funcs:
                        funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
                    if None in self.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):
                        self.session_interface.save_session(self, ctx.session, response)
                    return response
                在上述代码有两行代码
                    if None in self.after_request_funcs:
                    #funcs是所有after_request的函数列表,并用reversed做了反转
                    #这里就知道在after_request里为什么先注册的后执行
                        funcs = chain(funcs, reversed(self.after_request_funcs[None]))
                    for handler in funcs:
                        #在这里知道after_request的函数必须接受这response,并且要做返回
                        response = handler(response)
    
    4 我们知道3中就可以调用request属性,那么是怎么做到的呢
        当我们在3中的任意位置,都能调用request或者其他的。比如我们调用request.methons,他是如何找到当前请求的request的呢
        
        4.1 当我们调用request.methons的时候,我们先要看看request是什么
        源码如下:
            request = LocalProxy(partial(_lookup_req_object, "request"))#也就是LocalProxy对象
            
        4.2 当我们调用request.method就会返回属性methons属性给我吗,但是我们在LocalProxy根本没有methons属性,那么我们想到,既然没有这个属性,一定会走__getattr__
        源码如下:
            def __getattr__(self, name):
                #name就是methons
                if name == "__members__":
                    return dir(self._get_current_object())
                #_get_current_object中来取name也就是methods
                #_get_current_object()执行的结果是partial(_lookup_req_object, "request")()==》就是从ctx中取到request
                #下面的意思就是getattr(request,methons)
                return getattr(self._get_current_object(), name)
            上述代码的name,及时我们要找的methons,那他是从self._get_current_object()通过反射来拿的
            从下面的分析中 我们知道self._get_current_object()就是request
            
            4.2.1 self._get_current_object()的返回值是什么:
            通过下面的源码我们可以看到就是self.__local()的执行结果
            源码如下:
                def _get_current_object(self):
                    if not hasattr(self.__local, "__release_local__"):
                        return self.__local()
                    try:
                        return getattr(self.__local, self.__name__)
                    except AttributeError:
                        raise RuntimeError("no object bound to %s" % self.__name__)
                        
                4.2.1.1 self.__local()的执行结果是什么?首先要搞清楚self.__local是什么
                    我们发现self.__local是通过如下初始化得到的
                        def __init__(self, local, name=None):
                            object.__setattr__(self, "_LocalProxy__local", local)
                    那我们可以知道self.__local就是4.1中LocalProxy(partial(_lookup_req_object, "request"))的参数
                    也就是partial(_lookup_req_object, "request")偏函数
                    
                4.2.1.2 我们现在知道self.__local是partial(_lookup_req_object, "request")
                    那self.__local()就是partial(_lookup_req_object, "request")()执行
                    
                4.2.1.3 partial(_lookup_req_object, "request")相当于给_lookup_req_object函数传递了一个“request”参数
                    _lookup_req_object,源码如下:
                        #name就是request
                        def _lookup_req_object(name):
                            #Local中取得ctx
                            top = _request_ctx_stack.top
                            #top就是ctx
                            if top is None:
                                raise RuntimeError(_request_ctx_err_msg)
                            #ctx中去request 在吧request返回回去
                            return getattr(top, name)
                    我们从4.2.1.3.1得知 top就是ctx,getattr(top, name)就是从ctx找request,并且返回
                    4.2.1.2中self._local执行的结果就是request
                    
                    4.2.1.3.1 
                        上述代码中_request_ctx_stack.top的源码如下:
                        @property
                        def top(self):
                            try:
                                #返回了一开始存进去的ctx对象
                                return self._local.stack[-1]
                            except (AttributeError, IndexError):
                                return None
                        self._local也是Local对象 .stack就是在执行__getattr__
                        代码如下:
                            def __getattr__(self, name):
                                try:
                                    return self.__storage__[self.__ident_func__()][name]
                                except KeyError:
                                    raise AttributeError(name)
                这样_request_ctx_stack.top得到的结果就是ctx,4.2.1.3中的top = _request_ctx_stack.top;top就是ctx
    '''
    

    g对象

    from flask import Flask,g
    '''
    专门用来给开发者存储信息的,他只在同一个请求内有效
    '''
    app=Flask(__name__)
    
    @app.before_request
    def b_r():
        g.name="egon is sb"#存
        g.name="egon is dsb"
    
    @app.after_request
    def a_r(response):
        print(g.name)
        print(g.age)
        return response
    
    
    @app.route("/")
    def index():
        g.age="egon"
        print(g.name)#取
        return "ok"
    
    @app.route("/login")
    def login():
        return "login"
    
    if __name__ == '__main__':
        app.run()
    

    flask-script

    '''
    pip install flask-script
    bu用右键启动  改为命令行启动
    命令行:python s3.py runserver 或者 python3 s3.py runserver  s3是py文件的文件名
    '''
    from flask import Flask
    from flask_script import Manager
    app=Flask(__name__)
    manager=Manager(app)
    
    @app.route("/")
    def index():
        return "ojbk"
    
    '''
    命令行启动下面的函数
    python s3.py etom 123
    s3是py文件名  etom是函数名  123是参数 函数没有参数就不用谢
    '''
    @manager.command
    def etom(arg):
        print("我把excl导入到myslq")
        print(arg)
    
    '''
    命令行启动:
    python s3.py cmd -n egon -y haha
    python s3.py cmd -y hah  -n egon
    python s3.py cmd --you hah  -n egon
    python s3.py cmd --you hah  --name egon
    -n  --name -y --you:就相当于形参
    函数里的形参名要和dest一致
    '''
    @manager.option("-n","--name",dest="name")
    @manager.option("-y","--you",dest="you")
    def cmd(name,you):
        print(name,you)
    
    if __name__ == '__main__':
        manager.run()
    
  • 相关阅读:
    pycharm安装,svn使用,远程开发调试,接口测试,连接服务器
    scrapy回调函数传递参数
    python发送邮件
    python开发部署时新增数据库中表的方法
    python更新数据库脚本三种方法
    python中json.loads,dumps,jsonify使用
    chmod 命令
    find
    find 命令
    locate 命令
  • 原文地址:https://www.cnblogs.com/zqfzqf/p/12392252.html
Copyright © 2020-2023  润新知