Django Cookie和Session
【一】介绍
【1】起因
- HTTP协议四大特性
- 基于请求响应模式:客户端发送请求,服务端返回响应
- 基于TCP/IP之上:作用于应用层之上的协议
- 无状态:HTTP协议本身不保存客户端信息
- 短链接:1.0默认使用短链接,请求-响应后断开连接
- 因为无状态
- 导致客户端和服务端无法正常长时间的通讯
- 所以需要一种方法来打破这种情况
- Cookie和Session是Web开发中常用的两种持久化会话状态的方法
【2】Cookie和Session
(1)介绍
-
cookie
- Cookie是服务器发送到用户浏览器并保存在浏览器上的一块数据
- 他会在浏览器下一次向服务器发送请求时被携带并发送到服务器上
-
session
- Session是另一种保存用户数据的方法,但数据是保存到服务器端的
- Session通过生成一种叫做Session ID的唯一标识符,保存在cookie中或者通过URL传递,以便在多个请求中可以识别和跟踪用户
(2)关系
- session和cookie的主要关系是
- session通常使用cookie来存储Session ID
- 以便在多个请求之间跟踪用户
- 但是也可以通过其他方式(URL)
(3)异同
- 存储位置:
- cookie存储在客户端,session存储在服务端
- 安全性:
- 由于cookie存在客户端,所以安全性较低
- 如果信息是密码这种敏感信息,还是用session
- 生命周期:
- cookie可以设置过期时间,如果不设置时间,那么关闭浏览器时,cookie就会被删除
- session的生命周期通常由服务器设置,当用户关闭浏览器并长时间误操作,session也会过期然后删除
- 存贮容量:
- cookie的大小通常有限制(4KB)
- session理论上是没有大小限制的
【二】Django操作cookie
【1】语法
- 以HttpResponse为例
- 另外的两把斧也可以
(1)设置cookie
http_res = HttpResponse()
http_res.set_cookie(key, value)
(2)获取cookie
request.COOKIES.get(key)
(3)设置过期时间
- 不指定这个参数的话
- 那么cookie将是会话Cookie
- 即在浏览器关闭后会被删除
- max_age默认单位是秒
- 可以使用
datetime
模块的timedelta
快速换算单位 max_age = timedelta(days=1).total_seconds()
- 可以使用
- IE浏览器使用
expires
这个参数
http_res = HttpResponse()
http_res.set_cookie(key, value, max_age)
(4)注销cookie
http_res = HttpResponse()
http_res.delete_cookie(key)
- 视图层
def get_cookie(request):
res = request.COOKIES.get("name")
print(res)
return HttpResponse(res)
def set_cookie(request):
http_res = HttpResponse()
# 浏览器关闭后会被删除
http_res.set_cookie("name", "bruce")
# 5秒后这个cookie会被删除
# http_res.set_cookie("name", "bruce", max_age=5)
# 注销cookie
res = http_res.delete_cookie("name")
print(res)
return http_res
【2】示例
(1)装饰器登录功能
- 要求
- 功能界面
func
需要登录才可以使用,- 如果没有登录就跳转到登录界面
- 登录完成以后,自动跳转到主页
- 主页不需要进行登录验证
- 功能界面
- 前端(登录)
- 其他界面显示文字即可
- 直接HttpResponse
<form action="" method="post">
<p>username: <input type="text" name="username"></p>
<p>password: <input type="password" name="password"></p>
<button class="">提交</button>
</form>
- 视图层
login_decorator
:登录验证装饰器login
:登陆函数- home:主界面
func1
、func2
功能界面
def login_decorator(func):
def inner(request, *args, **kwargs):
if request.COOKIES.get("login_info"):
res = func(request, *args, **kwargs)
return res
return redirect('/login/')
return inner
def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
# 正常需要和数据库数据校验
# 这里简单一点
if username == "bruce" and password == "000":
response = redirect('/home/')
response.set_cookie("login_info", username + password)
return response
return render(request, 'login.html', locals())
def home(request):
return HttpResponse("主页")
@login_decorator
def func1(request):
return HttpResponse("func1")
@login_decorator
def func2(request):
return HttpResponse("func2")
(2)页面跳转登录功能
- 在原先的基础上
- 加上那个界面触发的登录
- 在登录成功以后返回到那个界面
- 精髓:发送POST请求带上GET请求的内容
def login_decorator(func):
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.COOKIES.get("login_info"):
res = func(request, *args, **kwargs)
return res
return redirect(f'/login/?next={next_url}')
return inner
def login(request):
# http://127.0.0.1:8000/login/?next=/func1/
# 此时发送的是POST请求
# 但是携带了get的内容
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
# 正常需要和数据库数据校验
# 这里简单一点
if username == "bruce" and password == "000":
next_url = request.GET.get("next")
next_url = next_url if next_url else '/home/'
response = redirect(next_url)
response.set_cookie("login_info", username + password)
return response
return render(request, 'login.html', locals())
【三】Django操作session
【0】准备
- session是保存在服务器的
- 那么Django就需要一个文件来保存session数据
- 这个文件就是在数据迁移时自动创建的表单
django_sessoin
- 即如果新项目想要使用session需要先迁移一下数据
【1】语法
(1)设置session
- 内部执行过程
- 产生一个随机字符串
- 保存随机字符串和加密数据
- 最后将随机字符串返回给浏览器,存储在cookie中
- 格式:
sessionid:随机字符串
- 格式:
- 添加多个键值对数据
- 最终还是对应一个
sessionid
- 最终还是对应一个
request.session['key'] = value
(2)获取session
- 内部执行过程
- 获取客户端发来的随机字符串
- 去存储session的
django_sessoin
表单中对比查询随机字符串 - 比对成功自动解密处理数据(根据key找value)
- 比对失败则
request.session
中的数据为None
request.session.get('key')
(3)设置过期时间
- value是整数:多少秒过期
- value是日期对象:
datetime.datetime
对象,会话将在这个指定的日期和时间过期。 - value是0:退出浏览器窗口就过期
- 不设置(None),过期策略将依赖于全局session配置
- 这是django的settings的文件中的session_cookie_age配置
- 默认是14天
- 可以不设置,设置了就必须要给值
- 过期会删除客户端和服务端的session,但是
- 客户端的自动删除了
- 服务端的出于性能考虑,并不会立即删除过期的session数据。
- 可以手动
clearsessions
命令来手动清理过期的session。
request.session.set_expiry(value)
(4)清空session
delete()
:- 清除当前用户所在服务端的session数据
- 但是会保留session的键key
- 如果下次用户来访问时session没有被填充
- 那么返回的就是一个空的session对象
request.session.delete()
flush()
:- 完全删除当前用户的所有session对象和相关数据
- 包括服务端和客户端
request.session.flush()
(5)多值和多session
-
同一个用户创建多个数据
- 报错的只有一个sessionid
-
同一个计算机,同一个浏览器对应相同的sessionid
-
同一个计算机,不同浏览器对应不同的sessionid
-
当session过期时,可能出现多个sessionid对应同一个浏览器
- 但是过期的数据不会持久化存储,会被定时清理掉
- 目的是为了节省服务器资源
- 手动清理
clearsessions
命令
-
视图层
def get_session(request):
res1 = request.session.get('sign')
print(f"session第一个数据:{res1}")
res2 = request.session.get("flag")
print(f"session第一个数据:{res2}")
return HttpResponse("获取session成功")
def set_session(request):
# session添加多个键值对,还是保存在一个sessionid中
request.session['sign'] = "hello"
request.session['flag'] = True
# 十秒后自动清除客户端和服务端的session
# request.session.set_expiry(10)
# 关闭浏览器就清除
# request.session.set_expiry(0)
return HttpResponse("添加session成功")
【2】Django配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密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,默认修改之后才保存(默认)
【3】示例
(1)页面跳转登录
- 和cookie的基本一样就是cookie改成session
def login_decorator(func):
def inner(request, *args, **kwargs):
next_url = request.get_full_path()
if request.session.get("login_info"):
res = func(request, *args, **kwargs)
return res
return redirect(f'/login/?next={next_url}')
return inner
def login(request):
# http://127.0.0.1:8000/login/?next=/func1/
# 此时发送的是POST请求
# 但是携带了get的内容
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
# 正常需要和数据库数据校验
# 这里简单一点
if username == "bruce" and password == "000":
next_url = request.GET.get("next")
next_url = next_url if next_url else '/home/'
response = redirect(next_url)
# response.sess("login_info", username + password)
request.session['login_info'] = f"{username}-{password}"
return response
return render(request, 'login.html', locals())