赞
踩
HTTP被设计为”无状态”,每次请求都处于相同的空间中。 在一次请求和下一次请求之间没有任何状态保持,我们无法根据请求的任何方面(IP地址,用户代理等)来识别来自同一人的连续请求。
对于HTTP的无状态性的原因,相关RFC里并没有解释,但联系到HTTP的历史以及应用场景,我们可以推测出一些理由:
上图很明显的展示了Django的session与cookie的实现原理。服务器会生成两份相同的cookie字符串(键值对),一份保存在本地,一份发向请求的浏览器。浏览器将收到的cookie字符串保存下来,当下次再发请求时,会将信息与这段cookie一同发送到服务器,服务器得到这段cookie会与本地保存的那份判断是否相同,如果相同就表示用户已经登录成功,保存用户登录成功的状态。
Django的session保存在数据库中的数据相当于一个大字典,key为cookie的字符串,value仍是一个字典,字典的key和value为用户设置的相关信息。这样就可以方便的存取session里面的信息。
1.cookie的定义
cookie 由服务器生成,保存在浏览器中,cookie就是一系列的键值对 key=value
构成字符串,键值对之间由一个分号和一个空格隔开。
2.cookie的作用:
登录状态的判定
3.cookie 的特点:
request.COOKIES
来获取cookie的工作原理
每个客户端最多保持三百个cookie,每个域名下最多20个Cookie(实际上一般浏览器现在都比这个多,如Firefox是50个),而每个cookie的大小为最多4K,不过不同的浏览器都有各自的实现。对于cookie的使用,最重要的就是要控制cookie的大小,不要放入无用的信息,也不要放入过多信息。
cookie的值是 如何传递的?
无论使用何种服务端技术,只要发送回的HTTP响应中包含如下形式的头,则视为服务器要求设置一个cookie:Set-cookie:name=name;expires=date;path=path;domain=domain
支持cookie的浏览器都会对此作出反应,即创建cookie文件并保存(也可能是内存cookie),用户以后在每次发出请求时,浏览器都要判断当前所有的cookie中有没有没失效(根据expires属性判断)并且匹配了path属性的cookie信息,如果有的话,会以下面的形式加入到请求头中发回服务端:Cookie: name="zj"; Path="/linkage"
服务端的动态脚本会对其进行分析,并做出相应的处理,当然也可以选择直接忽略。
请求参数:
请求的头中Cookie就是把所有的服务器之前返回的Cookie以分号;进行分割,拼成了一个字符串传给了服务器。
响应参数:
返回数据的头中有一系列的key为Set-Cookie的键值对
第一个Set-Cookie:JSESSIONID
这时用来实现会话的,如果是第一次访问,请求的参数中没有这个参数,服务器会生成一个JSESSIONID放在响应头中,下次在访问的时候,浏览器就会把这个参数带上 。
第一幅图中的Cookie中就有JSESSIONID,这说明已经不是第一次访问了
而第二幅图中返回的头中有JSESSIONID,说明这次的请求是第一次请求
这两幅图并不是同一次的请求和响应
第二个Set-Cookie
都是服务器返回的其它键值对,浏览器不用关心它们是什么意思,下次访问的时候直接在返回给服务端就是。
其中第二个Set-Cookie长得与其它不太一样,多了一个Expires,这个是表示这个键值对过期时间,如果过期了,下次请求浏览器就不会把这个键值对带过去
cookie 的属性选项
每个cookie都有一定的属性,如什么时候失效,要发送到哪个域名,哪个路径等等。这些属性是通过cookie选项来设置的,cookie选项包括:expires、domain、path、secure、HttpOnly。
在设置任一个cookie时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。在设置这些属性时,属性之间由一个分号和一个空格隔开。代码示例如下:
"key=name; expires=Thu, 25 Feb 2016 04:18:00 GMT; domain=ppsc.sankuai.com; path=/; secure; HttpOnly"
expires
expires选项用来设置“cookie 什么时间内有效”。expires其实是cookie失效日期,expires必须是 GMT 格式的时间(可以通过new Date().toGMTString()或者 new Date().toUTCString() 来获得)。
如expires=Thu, 25 Feb 2016 04:18:00 GMT表示cookie讲在2016年2月25日4:18分之后失效,对于失效的cookie浏览器会清空。如果没有设置该选项,则默认有效期为session,即会话cookie。这种cookie在浏览器关闭后就没有了。
expires 是 http/1.0协议中的选项,在新的http/1.1协议中expires已经由 max-age 选项代替,两者的作用都是限制cookie 的有效时间。expires的值是一个时间点(cookie失效时刻= expires),而max-age 的值是一个以秒为单位时间段(cookie失效时刻= 创建时刻+ max-age)。
另外,max-age 的默认值是 -1(即有效期为 session );若max-age有三种可能值:负数、0、正数。负数:有效期session;0:删除cookie;正数:有效期为创建时刻+ max-age
domain
和path
domain
表示的是cookie所在的域,默认为请求的地址,如网址为
www.test.com/test/test.aspx
, 那么domain默认为www.test.com
。
path
表示cookie
所在的目录,asp.net
默认为/,就是根目录。在同一个服务器上有目录如下:/test/,/test/cd/,/test/dd/,现设一个cookie1的path为/test/,cookie2的path为/test/cd/,那么test下的所有页面都可以访问到cookie1,而/test/和/test/dd/的子页面不能访问cookie2。这是因为cookie能让其path路径下的页面访问。
两者加起来就构成了 URL,domain和path一起来限制 cookie 能被哪些 URL 访问。
一句话概括:某cookie的 domain为“baidu.com”, path为“/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。
所以domain和path2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。
特别说明1:
发生跨域xhr请求时,即使请求URL的域名和路径都满足 cookie 的 domain 和 path,默认情况下cookie也不会自动被添加到请求头部中。
特别说明2:
domain是可以设置为页面本身的域名(本域),或页面本身域名的父域,但不能是公共后缀 public suffix。举例说明下:如果页面域名为 www.baidu.com, domain可以设置为“www.baidu.com”,也可以设置为“baidu.com”,但不能设置为“.com”或“com”。
secure
secure选项用来设置cookie只在确保安全的请求中才会发送。当请求是HTTPS或者其他安全协议时,包含 secure 选项的 cookie才能被发送至服务器。
默认情况下,cookie不会带secure选项(即为空)。所以默认情况下,不管是HTTPS协议还是HTTP协议的请求,cookie 都会被发送至服务端。但要注意一点,secure选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。
设置cookie
from django.shortcuts import render, HttpResponse
# 设置cookie
def set_cookie(request):
response = HttpResponse('设置cookie')
# 设置cookie
response.set_cookie('num', 10, max_age=3600 * 24 * 14)
return response
# 读取cookie
def get_cookie(request):
# 通过 键 获取值
num = request.COOKIES['num']
return HttpResponse(num)
from django.utils.datastructures import MultiValueDictKeyError # 记住用户名 def login(request): if request.method == 'POST': username = request.POST.get('username') pwd = request.POST.get('pwd') # remember = request.POST['remember'] try: remember = request.POST['remember'] except MultiValueDictKeyError as e: remember = 'xxx' # print(remember) # 不勾选 返回None 选中返回on if username == 'zs' and pwd == '123': # 1. 如果选中,就设置 cookie print(remember) # 不勾选 返回None 选中返回on if remember == 'on': response = HttpResponse('登录成功...') response.set_cookie('username', username, max_age=3600 * 24 * 14) return response # 获取cookie的值,第一次get 请求 是没有设置cookie的因此 返回默认值 '' username = request.COOKIES.get('username', '') # None return render(request, 'app01/login.html', {'username': username})
session定义
Session一般译作会话,牛津词典对其的解释是进行某活动连续的一段时间。从不同的层面看待session,它有着类似但不全然相同的含义。比如,在web应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在web应用的开发者开来,用户登录时我需要创建一个数据结构以存储用户的登录信息,这个结构也叫做session。
因此在谈论session的时候要注意上下文环境。而本文谈论的是一种基于HTTP协议的用以增强web应用能力的机制或者说一种方案,它不是单指某种特定的动态页面技术,而这种能力就是保持状态,也可以称作保持会话。
创建session可以概括为三个步骤:
cookie
:服务端只要设置Set-cookie头就可以将session的标识符传送到客户端,而客户端此后的每一次请求都会带上这个标识符,由于cookie可以设置失效时间,所以一般包含session信息的cookie会设置失效时间为0,即浏览器进程有效时间。至于浏览器怎么处理这个0,每个浏览器都有自己的方案,但差别都不会太大(一般体现在新建浏览器窗口的时候);
URL重写
:
所谓URL重写,顾名思义就是重写URL。试想,在返回用户请求的页面之前,将页面内所有的URL后面全部以get参数的方式加上session标识符(或者加在path info部分等等),这样用户在收到响应之后,无论点击哪个链接或提交表单,都会在再带上session的标识符,从而就实现了会话的保持。读者可能会觉得这种做法比较麻烦,确实是这样,但是,如果客户端禁用了cookie的话,URL重写将会是首选。
def set_session(request): # 设置session request.session['username'] = 'zs' request.session['age'] = 18 # request.session.set_expiry(2) # 2s后过期 # 默认是14天后过期, 0 表示关闭浏览器过期 # 5s 表示 5s后过期 return HttpResponse('设置session') def get_session(request): """获取session""" username = request.session['username'] age = request.session['age'] return HttpResponse(username + ":" + str(age)) # 删除session def clear_session(request): request.session.flush() # 将整条记录删除 request.session.clear() # 删除内容部分 # 删除指定的key del request.session['username'] return HttpResponse('清除成功')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。