zoukankan      html  css  js  c++  java
  • Flask请求流程超清大图

    补充一下

    request是在哪里产生的:

    class RequestContext(object): 
            # app就是flask对象
            self.app = app
            if request is None:
                request = app.request_class(environ) # Request(environ) 处理request
            self.request = request # 就是这里没错了
            self.url_adapter = app.create_url_adapter(self.request)
            self.flashes = None
            self.session = None

    请求流程

    session的存取过程

    session的取值过程位于上图的此部分

    Flask实例的open_session方法首先是取了session_interface的值--一个类(SecureCookieSessionInterface)的对象,调用了他的open_session方法,将取出来的值赋予了ctx.session,存储到了Local实例中

    session的存值过程

    则是调用了session_interface代表的类实例的save_session方法但是这里存在一个问题:

    class SecureCookieSessionInterface(SessionInterface):
        session_class = SecureCookieSession
        def open_session(self, app, request):
            return self.session_class() # ctx的session就是这个类的实例
        # 父类中的此方法,我给直接写到这里了,如果此函数返回False,save_session不会设置cookie
        def should_set_cookie(self, app, session):
            if session.modified: 
            # 如果session.modified为True就说明session修改过了,为什么说修改过了,看下面
                return True
            save_each = app.config['SESSION_REFRESH_EACH_REQUEST']
            # session.permanent在SessionMixin类中
            return save_each and session.permanent
    
        def save_session(self, app, session, response):
            # 保存session时会根据session的modified来判断将不将session写进cookie中,下面简写
            if not self.should_set_cookie(app, session):
                return
    
    
    # session的类
    class SecureCookieSession(CallbackDict, SessionMixin):
        def __init__(self, initial=None):
            def on_update(self):
                self.modified = True
            CallbackDict.__init__(self, initial, on_update)
            self.modified = False # 默认是False
    
    class CallbackDict(UpdateDictMixin, dict):
        def __init__(self, initial=None, on_update=None):
            dict.__init__(self, initial or ())
            self.on_update = on_update # 这个就是上面init定义的方法 
    
    class UpdateDictMixin(object):
        # 这个类中定义了__setitem__和__delitem__ 会去执行self.on_update,修改self.modified的值
        # 问题就出在这里,session["x"]=""才会去执行self.on_update,
        # 但是如果session["x"]对应的是个数据结构,修改这个数据结构中的元素并不会去执行elf.on_update,
        # session.modified就还是False,修不修改session就要看save_each and session.permanent了
        # 如果他们之间有一个false就不会去修改,可以直接看到save_each存在与配置中
        # ,而session.permanent在SessionMixin类中
        on_update = None
        def calls_update(name):
            def oncall(self, *args, **kw):
                rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
                if self.on_update is not None:
                    self.on_update(self)
                return rv
            oncall.__name__ = name
            return oncall
    
        def setdefault(self, key, default=None):
            modified = key not in self
            rv = super(UpdateDictMixin, self).setdefault(key, default)
            if modified and self.on_update is not None:
                self.on_update(self)
            return rv
    
        def pop(self, key, default=_missing):
            modified = key in self
            if default is _missing:
                rv = super(UpdateDictMixin, self).pop(key)
            else:
                rv = super(UpdateDictMixin, self).pop(key, default)
            if modified and self.on_update is not None:
                self.on_update(self)
            return rv
    
        __setitem__ = calls_update('__setitem__')
        __delitem__ = calls_update('__delitem__')
        clear = calls_update('clear')
        popitem = calls_update('popitem')
        update = calls_update('update')
        del calls_update
    
    
    # session.permanent相关的
    class SessionMixin(object):
         # 取值时走这个方法
        def _get_permanent(self):
            return self.get('_permanent', False)
        # 通过.设置值是走这个方法
        def _set_permanent(self, value):
            self['_permanent'] = bool(value)
        # 这里不明白,为他设置值的时候会去调用on_update修改modified = True,如果设置了他
        # SessionInterface中的should_set_cookie就会直接return True
        # 而如果没设置就直接return session.permanent就好了,为什么还要and save_each
        permanent = property(_get_permanent, _set_permanent)
        del _get_permanent, _set_permanent
    
        new = False
    
        modified = True
    

      

    将session存在其他地方

    要将session存在其他地方,主要是和Flask中的session_interface属性对应的类实例有关系的.这些类要提供save_session和open_session方法

    Flask的flask_session组件就提供了这些类

    安装

    pip install flask_session
    

    用法

    # 配置类,具体的配置是根据数据库类型设置的
    class Config(object):
        SECRET_KEY = "umsuldfsdflskjdf" # 加密用
        PERMANENT_SESSION_LIFETIME = timedelta(minutes=20)
        SESSION_TYPE = "redis"
        SESSION_REDIS = Redis(host='192.168.0.94', port='6379') # 数据库连接,可以用连接池
    
    
    from flask import Flask,session
    from flask_session import Session
    app = Flask(__name__)
    app.config.from_object('Config')
    Session(app)
    

    Session干了什么

    class Session(object):
        def __init__(self, app=None):
            self.app = app
            if app is not None:
                self.init_app(app)
    
        def init_app(self, app):
            # 为flase实例赋了新的实例
            app.session_interface = self._get_interface(app)
    
        def _get_interface(self, app):
            # 根据配置来匹配不同的类
            config = app.config.copy()
            config.setdefault('SESSION_TYPE', 'null')
            config.setdefault('SESSION_PERMANENT', True)
            config.setdefault('SESSION_USE_SIGNER', False)
            config.setdefault('SESSION_KEY_PREFIX', 'session:')
            config.setdefault('SESSION_REDIS', None)
            config.setdefault('SESSION_MEMCACHED', None)
            config.setdefault('SESSION_FILE_DIR',
                              os.path.join(os.getcwd(), 'flask_session'))
            config.setdefault('SESSION_FILE_THRESHOLD', 500)
            config.setdefault('SESSION_FILE_MODE', 384)
            config.setdefault('SESSION_MONGODB', None)
            config.setdefault('SESSION_MONGODB_DB', 'flask_session')
            config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
            config.setdefault('SESSION_SQLALCHEMY', None)
            config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')
    
            if config['SESSION_TYPE'] == 'redis':
                session_interface = RedisSessionInterface(
                    config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'memcached':
                session_interface = MemcachedSessionInterface(
                    config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'filesystem':
                session_interface = FileSystemSessionInterface(
                    config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
                    config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
                    config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'mongodb':
                session_interface = MongoDBSessionInterface(
                    config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
                    config['SESSION_MONGODB_COLLECT'],
                    config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
                    config['SESSION_PERMANENT'])
            elif config['SESSION_TYPE'] == 'sqlalchemy':
                session_interface = SqlAlchemySessionInterface(
                    app, config['SESSION_SQLALCHEMY'],
                    config['SESSION_SQLALCHEMY_TABLE'],
                    config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
                    config['SESSION_PERMANENT'])
            else:
                session_interface = NullSessionInterface()
    
            return session_interface        
    

      

  • 相关阅读:
    android实现点击短链接进入应用 并获得整个连接的内容
    机房收费系统=三层+设计模式
    【数据库】SQL优化方法汇总
    HBase 数据库检索性能优化策略--转
    How to fix “HTTP Status Code 505 – HTTP Version Not Supported” error?--转
    使用VBS控制声音
    MSG命令使用详解
    bat删除系统默认共享
    C#:消息队列应用程序
    读写XML文档时,去掉新增加节点的“空命名空间”(xmlns=””)
  • 原文地址:https://www.cnblogs.com/wwg945/p/8964463.html
Copyright © 2011-2022 走看看