zoukankan      html  css  js  c++  java
  • Flask框架(五) —— session源码分析

    session源码分析

    1、请求来了,执行__call__方法

    # 请求来了执行 __call__方法
    if __name__ == '__main__':
        app.__call__
        app.run()
    

    2、__call__方法

    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
            WSGI application. This calls :meth:`wsgi_app` which can be
            wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)
    
    

    3、调用__call__方法

        def wsgi_app(self, environ, start_response):
            # 1.得到request,和空的session
            # ctx是RequestContext的对象,对象里面有空的session和request
            ctx = self.request_context(environ)     
            error = None
            try:
                try:
                    # 2.从request中的cookie中取出value,解密过转成session对象 --> open_session
                    ctx.push()
                    # 3.路由映射到函数,执行函数,然后保存session --> save_session,请求结束
                    response = self.full_dispatch_request()
                except Exception as e:
                    error = e
                    response = self.handle_exception(e)
                except:
                    error = sys.exc_info()[1]
                    raise
                return response(environ, start_response)
            finally:
                if self.should_ignore_error(error):
                    error = None
                ctx.auto_pop(error)
                
    

    3.1、ctx = self.request_context(environ) --- 得到空的session

        # 1. 获得RequestContext对象 ---> ctx
        def request_context(self, environ):  
            return RequestContext(self, environ)
        
        
       	class RequestContext(object): 
            def __init__(self, app, environ, request=None):
                self.app = app
                if request is None:
                    request = app.request_class(environ)     # request_class = Request
                self.request = request    
                self.url_adapter = app.create_url_adapter(self.request)
                self.flashes = None
                self.session = None
                
    

    3.2、ctx.push() --- 调用open_session方法

        # 2.ctx.push() --- 调用open_session方法
        def push(self):
            """Binds the request context to the current context."""
            top = _request_ctx_stack.top
            if top is not None and top.preserved:
                top.pop(top._preserved_exc)
    
            # Before we push the request context we have to ensure that there
            # is an application context.
            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)
    
            # Open the session at the moment that the request context is available.
            # This allows a custom open_session method to use the request context.
            # Only open a new session if this is the first time the request was
            # pushed, otherwise stream_with_context loses the session.
            
            # 从request中的cookie中取出value,(有解密过程)转成session对象
            # 正常情况下此时session中有值了
            # 如果request中没有cookie,那么session中仍然没有值
            if self.session is None:
                # session_interface = SecureCookieSessionInterface()
                session_interface = self.app.session_interface 
                # 2.1 opensession(),SecureCookieSessionInterface类中
                self.session = session_interface.open_session(
                    self.app, self.request
                )
    
                if self.session is None:
                    self.session = session_interface.make_null_session(self.app)
    
    

    3.2.1、session_interface.open_session() --- 从通过session的名字取出cookie的值转成session

    # 2.1.session_interface.open_session()
    class SecureCookieSessionInterface(SessionInterface):
        def open_session(self, app, request):
            s = self.get_signing_serializer(app)
            if s is None:
                return None
            # 通过session的名字取出cookie的值,key:value形式,得到的是json格式的字符串
            val = request.cookies.get(app.session_cookie_name)
            if not val:
                return self.session_class()
            max_age = total_seconds(app.permanent_session_lifetime)
            try:
                # 将json格式字符串转成字典
                data = s.loads(val, max_age=max_age)
    			# 返回一个特殊的字典
                return self.session_class(data)
            except BadSignature:
                return self.session_class()
            
    

    3.3、self.full_dispatch_request() --- 路由分发,执行函数,写入session

    # 3.self.full_dispatch_request()
    	1 执行before_request
        2 执行视图函数
        3 把session写入
            if not self.session_interface.is_null_session(ctx.session):
                self.session_interface.save_session(self, ctx.session, response)
    
        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)
    		# 3.1 把session保存写入cookie
            return self.finalize_request(rv)
        
    

    3.3.1、self.finalize_request(rv) --- 调用save_session()保存写入session

    # 3.1.self.finalize_request(rv)
    	def finalize_request(self, rv, from_error_handler=False):
            response = self.make_response(rv)
            try:
                # 利用save_session 保存写入session
                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.3.1.1、self.process_response(response) --- 调用save_session方法
    # 保存写入session    
        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):
                # 调用save_session方法保存写入session
                self.session_interface.save_session(self, ctx.session, response)
            return response
        
    
    save_session()方法
    class SecureCookieSessionInterface(SessionInterface):
        def save_session(self, app, session, response):
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
    
            # If the session is modified to be empty, remove the cookie.
            # If the session is empty, return without setting the cookie.
            if not session:
                if session.modified:
                    response.delete_cookie(
                        app.session_cookie_name,
                        domain=domain,
                        path=path
                    )
    
                return
    
            # Add a "Vary: Cookie" header if the session was accessed at all.
            if session.accessed:
                response.vary.add('Cookie')
    
            if not self.should_set_cookie(app, session):
                return
    
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            samesite = self.get_cookie_samesite(app)
            expires = self.get_expiration_time(app, session)
            val = self.get_signing_serializer(app).dumps(dict(session))
            response.set_cookie(
                app.session_cookie_name,
                val,
                expires=expires,
                httponly=httponly,
                domain=domain,
                path=path,
                secure=secure,
                samesite=samesite
            )
    
  • 相关阅读:
    Object-C,NSSet,不可变集合
    NYIST 860 又见01背包
    NYIST 1070 诡异的电梯【Ⅰ】
    HDU 1542 Atlantis
    HDU 4756 Install Air Conditioning
    CodeForces 362E Petya and Pipes
    HDU 4751 Divide Groups
    HDU 3081 Marriage Match II
    UVA 11404 Palindromic Subsequence
    UVALIVE 4256 Salesmen
  • 原文地址:https://www.cnblogs.com/linagcheng/p/10401741.html
Copyright © 2011-2022 走看看