博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
django session源码剖析
阅读量:5151 次
发布时间:2019-06-13

本文共 5562 字,大约阅读时间需要 18 分钟。

首先要明白,session和cookie,session是保存在服务器端,cookie存储在浏览器上,我们称为客户端,客户端向服务端发送请求时,会将cookie一起发送给服务端。服务端接收到请求后,会去检查是否已经有该客户端的session信息,如果没有,则创建一个新的session对象,用于保存客户端的一些必要信息,如果从服务器上找到了该客户端的信息,则会将该信息加载到session里,

django之所以能实现登陆认证,依靠的是一个叫sessionid的东西,该id记录了你的认证信息,如果你不喜欢这个名称,你也可以通过修改settings配置SESSION_COOKIE_NAME

settings解说之session

# Cache to store session data if using the cache session backend.SESSION_CACHE_ALIAS = 'default'  # 这个值对应CACHES里面的key# Cookie name. This can be whatever you want.SESSION_COOKIE_NAME = 'sessionid'# The module to store session dataSESSION_ENGINE = 'django.contrib.sessions.backends.db'# class to serialize session dataSESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'########## CACHE ########### The cache backends to use.CACHES = {    'default': {        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',    }}

. 在request请求模块里,默认是不带session功能的,也就是说request没有session属性的,为何我们还能使用呢?因为session功能是以中间件形式提供,由于在settings里配置了MIDDLEWARE_CLASSES这个变量,同时将模块'django.contrib.sessions.middleware.SessionMiddleware'添加到项目里,Django1.8以后的版本改名为MIDDLEWARE,所以我们才能通过request.session方式设置session。那么这个中间件对我们的request做了些什么呢?

def process_request(self, request):        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, None)        request.session = self.SessionStore(session_key)class WSGIHandler(base.BaseHandler):    initLock = Lock()    request_class = WSGIRequest    def __call__(self, environ, start_response):       ...        try:            request = self.request_class(environ)            ...#通过上面这段代码,可以分析,request是django.core.handlers.wsgi.WSGIRequest()的实例#中间件首先从我们的请求request.COOKIES获取对应的cookie信息,这个信息最开始是从浏览器的cookie获取的,如果浏览器没有相应的cookie信息,则服务器会为这个浏览器创建一个cookie实例,本质上cookie对象就是一个继承了dict字典的对象,接着从cookie对象取出session_key,也就是cookie为 `sessionid `的值,,然后拿着这个值到self.SessionStore进行实例化,
class SessionStore(SessionBase):    """    A cache-based session store.    """    def __init__(self, session_key=None):        self._cache = caches[settings.SESSION_CACHE_ALIAS]  # 实例化时会通过settings配置加载一个用于存储缓存的媒介,该媒介用于存储session的,默认是媒介是引擎是db,即数据库,我们这里分析的是使用本地内存作为session缓存。caches会去导入settings配置的CACHES的backend存储引擎,并且做一些基本解析CACHES对应的key的参数配置,比如我们的`SESSION_CACHE_ALIAS`为default,那么会把default里的其他keys信息当成参数传到那个backend对象里进行实例化,最终赋值给session的self._cache变量        super(SessionStore, self).__init__(session_key)  # 调用父类的构造方法,    @property    def cache_key(self):        return KEY_PREFIX + self._get_or_create_session_key()  # 这个方法最终一定会获取到一个_session_key    def load(self):          """这个方法调用是在假如需要对session进行修改操作时,比如设置session操作,那么会调用父类的__setitem__方法    def __setitem__(self, key, value):        self._session[key] = value        self.modified = True   def _get_session(self, no_load=False):        """        Lazily loads session from storage (unless "no_load" is True, when only        an empty dict is stored) and stores it in the current instance.        """        self.accessed = True        try:            return self._session_cache        except AttributeError:            if self.session_key is None or no_load:                self._session_cache = {}            else:                self._session_cache = self.load()        return self._session_cache    _session = property(_get_session)首先父类去获取_session属性,如果是第一次访问,肯定是没有缓存session的,也就是return self._session_cache这个对象暂时没有这个属性,第一次访问时,是没有session_key的,所以会 self._session_cache = {}创建一个空字典存储session缓存。第二次请求时,这时候可以从请求cookie里获取到 _session_key,那么,这时服务器可能已经记录过客户端的session信息了,为什么说是可能呢?因为如果选择使用本地内存方式存储,如果重启服务器,那么session将丢失,但是浏览器上已经写入了cookie信息,保留了_session_key.我们假如服务器没有重启过,那么服务器就保留了浏览器的session信息,这时会去加载这个session信息"""        try:            session_data = self._cache.get(self.cache_key, None)  #         except Exception:            # Some backends (e.g. memcache) raise an exception on invalid            # cache keys. If this happens, reset the session. See #17810.            session_data = None        if session_data is not None:            return session_data        self._session_key = None        return {}    def create(self):        # Because a cache can fail silently (e.g. memcache), we don't know if        # we are failing to create a new session because of a key collision or        # because the cache is missing. So we try for a (large) number of times        # and then raise an exception. That's the risk you shoulder if using        # cache backing.        for i in range(10000):            self._session_key = self._get_new_session_key()            try:                self.save(must_create=True)            except CreateError:                continue            self.modified = True            return        raise RuntimeError(            "Unable to create a new session key. "            "It is likely that the cache is unavailable.")    def save(self, must_create=False):        if self.session_key is None:            return self.create()        if must_create:            func = self._cache.add        else:            func = self._cache.set        result = func(self.cache_key,                      self._get_session(no_load=must_create),                      self.get_expiry_age())        if must_create and not result:            raise CreateError    def exists(self, session_key):        return session_key and (KEY_PREFIX + session_key) in self._cache    def delete(self, session_key=None):        if session_key is None:            if self.session_key is None:                return            session_key = self.session_key        self._cache.delete(KEY_PREFIX + session_key)    @classmethod    def clear_expired(cls):        pass

转载于:https://www.cnblogs.com/zengchunyun/p/7055480.html

你可能感兴趣的文章
SpringBoot系列五:SpringBoot错误处理(数据验证、处理错误页、全局异常)
查看>>
kubernetes_book
查看>>
OpenFire 的安装和配置
查看>>
侧边栏广告和回到顶部
查看>>
https://blog.csdn.net/u012106306/article/details/80760744
查看>>
海上孤独的帆
查看>>
处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“Manag
查看>>
01: socket模块
查看>>
mysql触发器
查看>>
淌淌淌
查看>>
web页面实现指定区域打印功能
查看>>
win10每次开机都显示“你的硬件设置已更改,请重启电脑……”的解决办法
查看>>
C++有关 const & 内敛 & 友元&静态成员那些事
查看>>
函数积累
查看>>
Swift 入门之简单语法(六)
查看>>
shim和polyfill有什么区别
查看>>
〖Python〗-- IO多路复用
查看>>
栈(括号匹配)
查看>>
Java学习 · 初识 面向对象深入一
查看>>
源代码如何管理
查看>>