Django中的cookie和session的处理
Cookie与Session介绍
- Cookie:
- Cookie的由来:
因为HTTP是无状态的短连接,
所以它的执行情况和结果与前面的请求和之后的请求都没有直接关系;
所以,在请求与响应中的数据不会被保留;
但是,又有一些数据是我们必须保留的,比如浏览器中的当前用户的登录状态等等;
由此产生了cookie;用于保存服务器给浏览器设置的一些数据;
- Cookie的本质:
cookie本质就是一组组的键值对;
服务器保存在浏览器中的键值对;
浏览器在下次访问服务器时,会自动携带上这些键值对;
这样服务器就可以根据这些键值对来对浏览器进行识别;
- Cookie原理:
cookie由服务器生成;
在浏览器接收到响应时,自动在本地将cookie保存,
下次发送请求自动携带该信息;
- Session:
- Session来源
session依赖于cookie;
cookie本身最大只可以设置4096字节,且保存在客户的浏览器中,不够安全;
所以,引出了session,支持更多字节,且加密,保存在服务器;
session存在浏览器的cookie中,和服务器的数据库中;
Cookie用法
- 获取cookie:
- 从request中获取:
# 简单获取 request.COOKIES['key'] # get_signed_cookie() 获取 request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None) # get_signed_cookie方法的参数: # default: 默认值 # salt: 加密盐 # max_age: 后台控制过期时间
- 设置cookie:
- 从Response对象中设置:
# 获取Response对象 rep = HttpResponse(...) rep = render(request, ...) # 设置cookie rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐',...) # set_signed_cookie() 参数解析: """ - key, 键 - value='', 值 - max_age=None, 超时时间 - expires=None, 超时时间(IE requires expires, so set it if hasn't been already.) - path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问 - domain=None, Cookie生效的域名 - secure=False, https传输 - httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖) """
- 清除cookie
- 从Response对象中设置
# 获取Response对象 rep = redirect("/login/") rep.delete_cookie("user") # 删除用户浏览器上之前设置的user的cookie值
Session用法
- session相关用法:
# 获取、设置、删除Session中数据 request.session['k1'] request.session.get('k1',None) request.session['k1'] = 123 request.session.setdefault('k1',123) # 存在则不设置 del request.session['k1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 会话session的key request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查会话session的key在数据库中是否存在 request.session.exists("session_key") # 删除当前会话的所有Session数据 request.session.delete() # 删除当前的会话数据并删除会话的Cookie。 request.session.flush() 这用于确保前面的会话数据不可以再次被用户的浏览器访问 例如,django.contrib.auth.logout() 函数中就会调用它。 # 设置会话Session和Cookie的超时时间 request.session.set_expiry(value) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。
- Django中全局配置中的session配置:
# 来源:from django.conf import global_settings (457-485行) - 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) - 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 - 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() - 缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 - 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 - 其他公用设置项: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
Django中session的源码实现流程
- 请求第一次进来:
- 因为是第一次,所以浏览器没有cookie;
- 请求进来执行中间件的 process_request()方法;
- 因为中间件本身是一个类,在实例化时,最先执行__init__()方法;
- 执行__init__ 该方法, 实际是在类中封装了 SessionStore类;
def __init__(self, get_response=None): self.get_response = get_response # engine = django.contrib.sessions.backends.db engine = import_module(settings.SESSION_ENGINE) # self.SessionStore = django.contrib.sessions.backends.db.SessionStore self.SessionStore = engine.SessionStore
- 执行 process_request() 方法:实际是实例化了SessionStore对象,并且去获取cookie中的值,因为是第一次,session_key 的值为None
def process_request(self, request): # settings.SESSION_COOKIE_NAME = "sessionid" session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME) request.session = self.SessionStore(session_key)
- 实例化SessionStore(),执行__init__方法,因为该方法继承了父类,同时也执行父类的__init__方法,和父类的属性;在最后生成了一个空字典 _session
class SessionStore(SessionBase): def __init__(self, session_key=None): super(SessionStore, self).__init__(session_key) def load(self): try: s = self.model.objects.get( session_key=self.session_key, expire_date__gt=timezone.now() ) return self.decode(s.session_data) except (self.model.DoesNotExist, SuspiciousOperation) as e: if isinstance(e, SuspiciousOperation): logger = logging.getLogger('django.security.%s' % e.__class__.__name__) logger.warning(force_text(e)) self._session_key = None return {} # 父类 class SessionBase(object): TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_VALUE = 'worked' __not_given = object() def __init__(self, session_key=None): self._session_key = session_key self.accessed = False self.modified = False # self.serializer = "django.contrib.sessions.serializers.JSONSerializer" 序列化器 self.serializer = import_string(settings.SESSION_SERIALIZER) def _get_session(self, no_load=False): self.accessed = True try:
# 第一次请求进来,self._session_cahe未被定义,执行except下面的代码 return self._session_cache except AttributeError:
# self.session_key 是在实例化的时候被传进来的,第一次请求为None,条件成立 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)
- 实例化结束后,process_request() 执行完毕走视图函数;
- 视图函数结束后,执行process_response()方法;在该方法中,若设置了session,则会将session数据保存在数据库,若没有则正常通过;