【Django】源码分析之session生命周期

标签: djangosession源码代码分析python
1248人阅读 评论(3) 收藏 举报
分类:

Web应用中session是至关重要的一个概念,有了它http就有了状态。 我们才能方面的开发出各种基于用户的应用。说到session 不得不说cookies,不过cookies在服务端基本没有太多需要实现的逻辑,基本就是存取和报文格式之类,所以不做研究。 (下面是根据django1.8代码分析)

session在django源码中的主要配置(django/contrib/sessions),主要的几个点
* session的存取,浏览器交互
* session key 的生成 以及 内容的序列化(默认使用json序列化)
* session存储 默认存储在数据库中(cookies 还是文件 或者是db等)

总得来说还是比较简单,自己很容易也可以造个轮子。

本文地址 http://blog.csdn.net/orangleliu/article/details/75045962

概览

先看下django全局默认配置中session相关的地方, 我们可以根据需要自行修改

############
# SESSIONS #
############

SESSION_CACHE_ALIAS = 'default'                         # Cache to store session data if using the cache session backend.
SESSION_COOKIE_NAME = 'sessionid'                       # Cookie name. This can be whatever you want.
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2               # Age of cookie, in seconds (default: 2 weeks).
SESSION_COOKIE_DOMAIN = None                            # A string like ".example.com", or None for standard domain cookie.
SESSION_COOKIE_SECURE = False                           # Whether the session cookie should be secure (https:// only).
SESSION_COOKIE_PATH = '/'                               # The path of the session cookie.
SESSION_COOKIE_HTTPONLY = True                          # Whether to use the non-RFC standard httpOnly flag (IE, FF3+, others)
SESSION_SAVE_EVERY_REQUEST = False                      # Whether to save the session data on every request.
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                 # Whether a user's session cookie expires when the Web browser is closed.
SESSION_ENGINE = 'django.contrib.sessions.backends.db'  # The module to store session data
SESSION_FILE_PATH = None                                # Directory to store session files if using the file session module. If None, the backend will use a sensible default.
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'  # class to serialize session data
  • 在浏览器端也是通过cookie来存储session的name和key(完全基于cookie),所以有一些cookies属性需要设置
  • django中session模块是以中间件的形式提供的(在MIDDLEWARE_CLASSES中设置) 会在response阶段对session进行处理 设置session cookie
  • session 对象有这几个属性 key ,data ,过期时间, 通过session表很容易看到
  • 存储的过程: session内容存在一个字典中,对字典进行序列化,然后hmc加salt的一次hash,”hashvalue:序列化数据” 在用base64编码一次,把session data变成string在存储

说说源码

简单描述下最核心的2个问题,session生成的过程? session 取出更新的过程?

session表的定义 django/contrib/sessions/base_session.py

class AbstractBaseSession(models.Model):
    session_key = models.CharField(_('session key'), max_length=40, primary_key=True)
    session_data = models.TextField(_('session data'))
    expire_date = models.DateTimeField(_('expire date'), db_index=True)

简单的流程

session_dict--> encode(session_dict) --> 存储

默认的 SESSION_ENGINE 是 ‘django.contrib.sessions.backends.db’, 看看这里基本就知道session操作了,还是上面的流程

看看session的获取

根据 cookies  sessionid 获取 session key --->  获取数据 ----> decode 数据得到 session_dict

decode , encode 主要在 django/contrib/sessions/backends/base.py 中,也很简单。

    def encode(self, session_dict):
        "Return the given session dictionary serialized and encoded as a string."
        serialized = self.serializer().dumps(session_dict)
        hash = self._hash(serialized)
        return base64.b64encode(hash.encode() + b":" + serialized).decode('ascii')

    def decode(self, session_data):
        encoded_data = base64.b64decode(force_bytes(session_data))
        try:
            # could produce ValueError if there is no ':'
            hash, serialized = encoded_data.split(b':', 1)
            expected_hash = self._hash(serialized)
            if not constant_time_compare(hash.decode(), expected_hash):
                raise SuspiciousSession("Session data corrupted")
            else:
                return self.serializer().loads(serialized)
        except Exception as e:
            # ValueError, SuspiciousOperation, unpickling exceptions. If any of
            # these happen, just return an empty dictionary (an empty session).
            if isinstance(e, SuspiciousOperation):
                logger = logging.getLogger('django.security.%s' % e.__class__.__name__)
                logger.warning(str(e))
            return {}

session 使用的时候会涉及到一些 settings中配置,主要看 django.contrib.session.middleware.SessionMiddleware 就行了,session使用的好例子。

调试

下面是采用db存储下,一些调试结果, 参照上面 encode, decode 部分代码

请求进来之后 到 SessionMiddleware , process_request 方法
读取配置中 session 的 cookie name 为 'sessionid', 从cookies取出 sessionid 的cookie,它的值就是 django中一个 session key
然后从存储取出 session 对象,放在 request  对象中。

例如 session_key 为 'ywptdguqbjt7ws6ysp4ztyx18vsazrx0'
查找session的 序列化配置 默认为 'django.contrib.sessions.serializers.JSONSerializer'
根据session key,当前时间 从数据库查找没过期的记录
然后decode session_data,b64decode 得到 '10754efe4d110a7aba657311c37513cee5841cd9:{}' 格式为 hashvalue:serializeddata 两部分
hashvalue 是对 serializeddata 之后的字符串做校验之用,防止有人直接篡改数据库,如果 hashvalue == hash(serializeddata ), 然后 反序列化
serializeddata 得到一个 dict对象。

存,更新 session ,数据加工顺序相反。

经验

最好有分布式内存缓存的集群来存储。 auth验证的时候会大量的读取session。

session清除

Django 优化小技巧之清除过期session 使用数据库存储session不会主动删除,过期数据太多势必影响性能。

db + cache来存储session

这样做可以提高性能,虽然存储时候慢了一点点,读取会快很多,适合session读取较多场合。

如果session是存储在关系型数据库中,是可以在数据库上在配置一个cache层的,django提供了这么一种机制。如果开启了cache,如果应用中有session相关操作,要注意从cached_db 和从db中直接取出session产生的内容过期问题。因为session的值 即会在数据库中持久化,也会在cache引擎中存储(在过期之前)。 最好操作 cached_db 会自动同步相同的操作到db中

3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1308349次
    • 积分:17201
    • 等级:
    • 排名:第588名
    • 原创:444篇
    • 转载:35篇
    • 译文:22篇
    • 评论:106条
    感谢支持
    一起玩
    统计