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        

  

 

posted @ 2018-04-27 21:07  瓜田月夜  阅读(280)  评论(0编辑  收藏  举报