zoukankan      html  css  js  c++  java
  • python-flask-请求源码流程

    启动先执行manage.py 中的    app.run()

    class Flask(_PackageBoundObject):
       def
    run(self, host=None, port=None, debug=None, **options):   from werkzeug.serving import run_simple   try:   #run_simple 是werkzeug 提供的方法,会执行第三个参数 self()   run_simple(host, port, self, **options)

    执行app(),对象()表示调用对象的__call__方法

    class Flask(_PackageBoundObject):
       def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response)

    又调用了app.wsgi_app方法

    class Flask(_PackageBoundObject):
       def wsgi_app(self, environ, start_response): #1.
         ctx = self.request_context(environ)
         #self.request_context #2. ctx.push()
         try: try:
              #3.执行视图函数
    response = self.full_dispatch_request() except Exception as e: error = e
              #4. response
    = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally:
           #5.
    ctx.auto_pop(error)

    第1步:执行app.request_context方法,把请求的相关信息传进去了

    class Flask(_PackageBoundObject):
       def request_context(self, environ): return RequestContext(self, environ)

    返回了一个RequestContext类的实例对象

    class RequestContext(object):
       def __init__(self, app, environ, request=None): self.app = app if request is None: request = app.request_class(environ)
           #app.request_class = Request self.request
    = request self.session = None

    在init构造方法中注意app又调用了request_class方法,也就是Request 实例一个对象,

    那么第1步我们知道:

    ctx是一个RequestContext对象,这个对象里面封装了两个主要的属性,一个是self.request = Request实例的对象,Request对象里面封装了请求进来的所有数据;
    另外一个是self.session = None就可以了

    第2步:执行ctx.push()方法

    因为ctx是RequestContext类的对象,那我们就要去RequestContext类中找push方法

    class RequestContext(object):
       def push(self):      #2.1. app_ctx = _app_ctx_stack.top if app_ctx is None or app_ctx.app != self.app: app_ctx = self.app.app_context()
                # self.app.app_context = app.app_context = AppContext(app) app_ctx.push()

         #2.2.
         _request_ctx_stack.push(self)
            #_request_ctx_stack = LocalStack()
         #2.3.
            self.session = self.app.open_session(self.request)

            #判断没有 secret_key时:
            if self.session is None:
                self.session = self.app.make_null_session()
                #raise RuntimeError('The session is unavailable because no secret ''key was set.)

    第2.1步:到_app_ctx_stack这个栈中取最后一个数据,如果未取到或者取到的不是当前的app,就调用app.app_context()方法,就是新实例一个上下文app_ctx对象,再执行app_ctx.push()方法     (在这再次强调,因为app_ctxAppContext对象,就要先去AppContext类中找push方法),

    class AppContext(object):
       def push(self): _app_ctx_stack.push(self) #把新创建的app_ctx上下文app对象添加到了_app_ctx_stack这个栈中 appcontext_pushed.send(self.app) #在这里遇到了第一个信号,请求app上下文push时执行

    第2.2步:LocalStack类的对象调用push方法

    class LocalStack(object):
       def push(self, obj): rv = getattr(self._local, 'stack', None) #self._local = Local()
         #第一次的时候rv肯定是None
    if rv is None: self._local.stack = rv = [] #Local对象 .stack = rv = [] 就执行了对象的 __setattr__方法 rv.append(obj) #把 ctx对象添加到Local类的列表中 return rv
    try:
        from greenlet import getcurrent as get_ident
    except ImportError:
        try:
            from thread import get_ident
        except ImportError:
            from _thread import get_ident
    
    class Local(object):    
        def __init__(self):
            object.__setattr__(self, '__storage__', {}) #这里为什么用object.__setattr__ 而不是直接用self.__storage__={}
            object.__setattr__(self, '__ident_func__', get_ident) #如果用self的方式设置属性,就会触发self的__setattr__方法,就会无限的循环
      
    def __setattr__(self, name, value): ident = self.__ident_func__() storage = self.__storage__ try: storage[ident][name] = value # {"唯一标识1":{"stack":[]},"唯一标识2":{"stack":[]}} 和本地线程类似 except KeyError: storage[ident] = {name: value}

     第2.3步:给ctx.session赋值,执行app.open_session(ctx.request)

    class Flask(_PackageBoundObject):
       def open_session(self, request): return self.session_interface.open_session(self, request)
         #return SecureCookieSessionInterface().open_session(app, request)
         #所以就要去SecureCookieSessionInterface类找open_session方法
    class SecureCookieSessionInterface(SessionInterface):
       def open_session(self, app, request): # 查看 是否有secret_key s = self.get_signing_serializer(app) if s is None: return None
    val
    = request.cookies.get(app.session_cookie_name) # 请求第一次来的时候取不到值 if not val: return self.session_class() #返回了一个 类似字典 max_age = total_seconds(app.permanent_session_lifetime) try: data = s.loads(val, max_age=max_age) #loads 作用是: 反序列化+解析乱码 return self.session_class(data) ##返回了一个 类似字典对象,对象里面有data except BadSignature: return self.session_class()

    那么第2步我们知道:

    1.把app_ctx上下文对象添加到了_app_ctx_stack这个栈中
    2.把 ctx请求对象添加到Local类的列表中
    3.执行open_session方法,把session加载到内

     第3步:app.full_dispatch_request()   执行视图函数 

    class Flask(_PackageBoundObject):
        def full_dispatch_request(self):
            #3.1
            self.try_trigger_before_first_request_functions()
            try:
                request_started.send(self)     # 信号 - 请求到来前执行
                # 3.2
                rv = self.preprocess_request()
                if rv is None:
                    # 3.3 如果所有的中间件都通过了, 执行视图函数
                    rv = self.dispatch_request()
         #3.4
            return self.finalize_request(rv)

    第3.1步:找到所有的 执行一次的 伪中间件 执行

    class Flask(_PackageBoundObject):
        def try_trigger_before_first_request_functions(self):
    
            with self._before_request_lock:
                for func in self.before_first_request_funcs:
                    func()

    第3.2步:找到所有的 伪中间件的执行

    class Flask(_PackageBoundObject):
        def preprocess_request(self):
    
            funcs = self.before_request_funcs.get(None, ())
            for func in funcs:
                rv = func()
                if rv is not None:
                    return rv

    第3.3步:

    class Flask(_PackageBoundObject):
        def dispatch_request(self):
            #获取请求的ctx对象中的request数据
            req = _request_ctx_stack.top.request
            #获取请求的url
            rule = req.url_rule
            #执行视图函数
            return self.view_functions[rule.endpoint](**req.view_args)

    第3.4步:

    class Flask(_PackageBoundObject):
        def finalize_request(self, rv, from_error_handler=False):
            response = self.make_response(rv)   #通过make_response方法后就可以对返回值进行设置响应头等数据了
            try:
           #3.4.1 response
    = self.process_response(response) request_finished.send(self, response=response) #信号 - 请求结束后执行 return response

    第3.4.1步:

    class Flask(_PackageBoundObject):
        def process_response(self, response):
            ctx = _request_ctx_stack.top
            #找到所有的 after_request 伪中间件执行
            funcs = ctx._after_request_functions
            for handler in funcs:
                response = handler(response)
            # 3.4.1.1 如果有session就执行self.save_session方法
            if not self.session_interface.is_null_session(ctx.session):
         # self.session_interface = SecureCookieSessionInterface()
           #3.4.1.2
            self.save_session(ctx.session, response)
    return response

    第3.4.1.1步: 到SecureCookieSessionInterface类中找is_null_session方法,发现没有,就去它基类SessionInterface中找

    class SessionInterface(object):
        def is_null_session(self, obj):
            #判断ctx.session 是不是 self.null_session_class = NullSession 类或者它派生类的对象
            return isinstance(obj, self.null_session_class)

    第3.4.1.2步:执行了SecureCookieSessionInterface类的save_session方法

    class Flask(_PackageBoundObject):
        def save_session(self, session, response):
            return self.session_interface.save_session(self, session, response)
            # return SecureCookieSessionInterface().save_session(self, session, response)
    class SecureCookieSessionInterface(SessionInterface):
        def save_session(self, app, session, response):
            #给响应设置cookie
            response.set_cookie(app.session_cookie_name, val,
                                expires=expires, httponly=httponly,
                                domain=domain, path=path, secure=secure)

    补充:自定义session

    from flask import Flask,request,session
    app = Flask(__name__)
    app.secret_key = 'sdfsdfsd'
    from flask.sessions import SessionInterface,SessionMixin
    import uuid
    import json
    from flask.sessions import SessionInterface
    from flask.sessions import SessionMixin
    from itsdangerous import Signer, BadSignature, want_bytes
    
    class MySession(dict, SessionMixin):
        def __init__(self, initial=None, sid=None):
            self.sid = sid
            self.initial = initial
            super(MySession, self).__init__(initial or ())
    
        def __setitem__(self, key, value):
            super(MySession, self).__setitem__(key, value)
    
        def __getitem__(self, item):
            return super(MySession, self).__getitem__(item)
    
        def __delitem__(self, key):
            super(MySession, self).__delitem__(key)
    
    
    class MySessionInterface(SessionInterface):
        session_class = MySession
        container = {
            # 'asdfasdfasdfas':{'k1':'v1','k2':'v2'}
            # 'asdfasdfasdfas':"{'k1':'v1','k2':'v2'}"
        }
    
        def __init__(self):
            pass
            # import redis
            # self.redis = redis.Redis()
    
        def _generate_sid(self):
            return str(uuid.uuid4())
    
        def _get_signer(self, app):
            if not app.secret_key:
                return None
            return Signer(app.secret_key, salt='flask-session',
                          key_derivation='hmac')
    
        def open_session(self, app, request):
            """
            程序刚启动时执行,需要返回一个session对象
            """
            sid = request.cookies.get(app.session_cookie_name)
            if not sid:
                # 生成随机字符串,并将随机字符串添加到 session对象中
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            signer = self._get_signer(app)
            try:
                sid_as_bytes = signer.unsign(sid)
                sid = sid_as_bytes.decode()
            except BadSignature:
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            # session保存在redis中
            # val = self.redis.get(sid)
            # session保存在内存中
            val = self.container.get(sid)
    
            if val is not None:
                try:
                    data = json.loads(val)
                    return self.session_class(data, sid=sid)
                except:
                    return self.session_class(sid=sid)
            return self.session_class(sid=sid)
    
        def save_session(self, app, session, response):
            """
            程序结束前执行,可以保存session中所有的值
            如:
                保存到resit
                写入到用户cookie
            """
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            expires = self.get_expiration_time(app, session)
    
            val = json.dumps(dict(session))
    
            # session保存在redis中
            # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
            # session保存在内存中
            self.container.setdefault(session.sid, val)
    
            session_id = self._get_signer(app).sign(want_bytes(session.sid))
    
            response.set_cookie(app.session_cookie_name, session_id,
                                expires=expires, httponly=httponly,
                                domain=domain, path=path, secure=secure)
    
    
    
    app.session_interface = MySessionInterface()
    # app.session_interface = Foo()
    # app.session_interface
    # app.make_null_session()
    @app.route('/index')
    def index():
        print('网站的所有session',MySessionInterface.container)
        print(session)
        session['k1'] = 'v1'
        session['k2'] = 'v2'
        del session['k1']
    
        # 在内存中操作字典....
        # session['k1'] = 'v1'
        # session['k2'] = 'v2'
        # del session['k1']
    
        return "xx"
    
    if __name__ == '__main__':
        app.__call__
        app.run()
    自定义类似django的session

    第4步:

    class Flask(_PackageBoundObject):
        def handle_exception(self, e):
            got_request_exception.send(self, exception=e)    #信号 - 请求执行出现异常时执行

    第5步: 执行了RequestContextpop 方法

    class RequestContext(object):
        def auto_pop(self, exc):
            else:
                self.pop(exc)
    class RequestContext(object):
        def pop(self, exc=_sentinel):
         try:
              if not self._implicit_app_ctx_stack:
             #5.1
                  self.app.do_teardown_request(exc)
    finally:
           # 请求结束时 request上下文的栈中就把请求pop掉 rv
    = _request_ctx_stack.pop()
               if app_ctx is not None:
              #5.2
                  app_ctx.pop(exc)

    第5.1步: 执行  app.do_teardown_request方法

    class Flask(_PackageBoundObject):
        def do_teardown_request(self, exc=_sentinel):
         # 信号 - 请求执行完毕后自动执行(无论成功与否)
            request_tearing_down.send(self, exc=exc)

    第5.2步:

    class AppContext(object):
        def pop(self, exc=_sentinel):
            try:
                if self._refcnt <= 0:
              #5.2.1

                    self.app.do_teardown_appcontext(exc)
         # 信号 - 请求上下文pop时执行
    appcontext_popped.send(self.app)

    第5.2.1步:

    class Flask(_PackageBoundObject):
        def do_teardown_appcontext(self, exc=_sentinel):
            # 信号 - 请求上下文执行完毕后自动执行(无论成功与否)
            appcontext_tearing_down.send(self, exc=exc)
     
  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/liuwei0824/p/8304097.html
Copyright © 2011-2022 走看看