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
            )
    
  • 相关阅读:
    linux ls
    ExtJs 弹出窗口
    Redhat5 装中文
    Linux下配置JDK以及报cannot restore segment prot after reloc: Permission denied错解决方案
    工具
    得到剪切的图片
    label button等设置不同颜色的标题
    UITableView UITextField 键盘挡住
    给出颜色生成图片
    一个不错的学习网站
  • 原文地址:https://www.cnblogs.com/linagcheng/p/10401741.html
Copyright © 2011-2022 走看看