session源码流程

链接

app.py

# session执行流程源码初探

from flask import Flask

# 1. 实例化Flask对象
app = Flask(__name__)

# 2. 设置路由
"""
self.url_map=Map()  url.map是一个对象,里面可以看作是一个列表或者字典,保存了所有的路由关系
app.url_map = [
    ('/index',index),
    ('/login',login),
]
"""
@app.route('/index')
def index():
    return "index"


if __name__ == '__main__':
    # 3. 启动socket服务端
    app.run()

#app.py
class Flask(_PackageBoundObject):
    # 4. 用户请求到来
    def __call__(self, environ, start_response):
        """
        environ:是请求相关的所有数据,由wsgi做了初步的封装
        start_response:用于设置响应相关数据

        """
        return self.wsgi_app(environ, start_response)

    #……
    def request_context(self, environ):

        return RequestContext(self, environ)
    #……
    def wsgi_app(self, environ, start_response)
        '''        
        1.获取environ并对其进行再次封装
        2.从environ中获取名称为session的cookie,解密,反序列化
        3.把两个东西放到“某个神奇”的地方       
        '''
        #ctx = RequestContext(self, environ)  #self就是app对象,environ是请求相关的原始数据
        #ctx.request = request_class(environ)
        #ctx.session = None
        ctx = self.request_context(environ) #这一句代码作用如上
        error = None
        try:
            try:
                # 将ctx放到“空调上”
                # 执行 SecureCookieSessionInterface.open_session,去cookie中获取值并给ctx.session重新赋值
                ctx.push()
                # 5 去执行视图函数
                # 6 "某个神奇" 位置清空,到此整个请求响应就终止了
                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
                '''
                7. "某个神奇"获取session加密,序列化,写入cookie
                
                '''
            ctx.auto_pop(error)

    session_interface = SecureCookieSessionInterface()

    #……
    def dispatch_request(self):

        req = _request_ctx_stack.top.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)
        rule = req.url_rule
        # if we provide automatic options for this URL and the
        # request came with the OPTIONS method, reply automatically
        if (
            getattr(rule, "provide_automatic_options", False)
            and req.method == "OPTIONS"
        ):
            return self.make_default_options_response()
        # otherwise dispatch to the handler for that endpoint
        return self.view_functions[rule.endpoint](**req.view_args)

    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)
    def finalize_request(self, rv, from_error_handler=False):

        response = self.make_response(rv)
        try:
            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

    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

    # app.wsgi_app
    # app.request_class
    # app.session_interface
    # app.full_dispatch_request

session.py

class SecureCookieSessionInterface(SessionInterface):
    """The default session interface that stores sessions in signed cookies
    through the :mod:`itsdangerous` module.
    """

    #: the salt that should be applied on top of the secret key for the
    #: signing of cookie based sessions.
    salt = "cookie-session"
    #: the hash function to use for the signature.  The default is sha1
    digest_method = staticmethod(hashlib.sha1)
    #: the name of the itsdangerous supported key derivation.  The default
    #: is hmac.
    key_derivation = "hmac"
    #: A python serializer for the payload.  The default is a compact
    #: JSON derived serializer with support for some extra Python types
    #: such as datetime objects or tuples.
    serializer = session_json_serializer
    session_class = SecureCookieSession

    def get_signing_serializer(self, app):
        if not app.secret_key:
            return None
        signer_kwargs = dict(
            key_derivation=self.key_derivation, digest_method=self.digest_method
        )
        return URLSafeTimedSerializer(
            app.secret_key,
            salt=self.salt,
            serializer=self.serializer,
            signer_kwargs=signer_kwargs,
        )

    #请求进来执行open_session
    def open_session(self, app, request):
        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)
            return self.session_class(data)
        except BadSignature:
            return self.session_class()

    # 请求走执行save_session
    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,
        )

 

posted @ 2020-07-03 15:36  zh_小猿  阅读(254)  评论(0编辑  收藏  举报