Cookie的由来,如何理解HTTP协议是无状态的。
无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。
比如我们在没引入cookie验证之前,我们输入http://127.0.0.1:8000/login/进入页面登录操作,理论上我们必须完成登录后才能进行后续操作,如果服务器不告诉浏览器就是把键值对交给浏览器,让浏览器与服务器建立关联。那么我们输入http://127.0.0.1:8000/student/同样也可以完成与页面的交互工作,从而失去了登录操作的意义。
一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。
状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。
什么是Cookie
Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。
Cookie的原理
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。
查看Cookie
我们使用Chrome浏览器,打开开发者工具。
Django中操作Cookie
设置cookie,rep是获取响应的对象
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
获取Cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
为了进一步理解cookie的用法,我们这边由浅到深举个案例
案例1:
http://127.0.0.1:8000/login/进入页面登录操作,登录成功后页面跳转去http://127.0.0.1:8000/home/并提示已登录成功,同时将cookie以键值对的方式交付给浏览器,当输入http://127.0.0.1:8000/home/时浏览器会判断如果有cookie的话就返回提示已登录成功页面,否则让用户重新登录,从而实现了login页面与home页面的关联。
- login.py
def login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('psd')
if username == "abc" and password == "123456":
rep = redirect('/home/')
rep.set_signed_cookie('loging', '123', salt="adoef")
return rep
return render(request, 'login.html')
- home.py
def home(request):
ret = request.get_signed_cookie('loging',default='0',salt="adoef")
if ret == "123":
return render(request,'home.html')
else:
return redirect('/login/')
- 注销
def loginout(request):
rep = redirect('/login/')
rep.delete_cookie('loging')
return rep
由下图可知http://127.0.0.1:8000/home/时,因为没找到cookie,所以就跳转到http://127.0.0.1:8000/login/页面。正确登录后就返回到home页面
案例二
在实务中我们登录后要操作页面不限于home页面,还有很多页面,由于实现的功能是一样的(就是把多页通过cookie取得关联)这时我们需要做个函数装饰器,当调用def home(resquest)时第一时间调用函数装饰器里对应的函数。
第一步:函数装饰器
def login_check(fn):
def innr(request, *args, **kwargs):
ret = request.get_signed_cookie('loging', default='0', salt='adoef')
if ret == '123':
return fn(request, *args, **kwargs)
else:
next_url = request.path_info
return redirect('/login/?next={}'.format(next_url))
return innr
第二步:
- login.py
def login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('psd')
next_url = request.GET.get('next')
if username == "abc" and password == "123456":
if next_url:
rep = redirect(next_url)
else:
rep = redirect('/home/')
rep.set_signed_cookie('loging', '123', salt="adoef")
return rep
return render(request, 'login.html')
- 加装饰器
@login_check
def student(request):
return render(request, 'student.html')
@login_check
def home(request):
return render(request, 'home.html')
- login.html
action="{{ request.get_full_path }}"
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="{{ request.get_full_path }}" method="post">
{% csrf_token %}
<p>用户名
<input type="text" name="username">
</p>
<p>请输入密码
<input type="password" name="psd">
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
</body>
</html>
我们输入http://127.0.0.1:8000/student/时,因为浏览器找不到cookies,所以按照redirect('/login/?next={}'.format(next_url)),跳去
http://127.0.0.1:8000/login/?next=/student/。
同时对应跳去login.py,当成功登录后返回request.path_info对应的路径。
不关闭浏览器(django默认关闭浏览器后cookie失效),直接输入
http://127.0.0.1:8000/home/,因为cookie仍有效,所以对应的页面不会跳转去登录