cookie
起源
Web应用程序是使用HTTP协议传输数据的。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。就相当于你和女朋友一块去去逛商场,本来两人约定说好的AA制。但是你将你需要的东西放入A购物车,你女朋友将贵重物品放入B购物车,这时结账的时候,你购买第一件商品之后售货员就无法判断第二次购买行为是你还是你女朋友的了。理论上一个用户的所有请求都属于一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。所以你无论何时所购买的所有商品都属于同一个会话。
为了解决这种问题,Cookie应运而生。
服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,也就是从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,这些都是Cookies的功用。另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入Cookies,以便在最后付款时提取信息。
不可跨域性
cookie是由服务端向客户端颁发的,但是不同的网站之间的cookie不可串用,这就是cookie的不可跨域性,判断一个网站是否能操作另一个网站Cookie的依据是域名。任何服务端都无法实现这一功能,这是浏览器做的事。虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。
实质
Cookie实际上是存储在本机上一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
利弊
由于cookie是一段以键值对存储的字典信息,并且键值对都是字符串形式的。能够存储部分用户信息,所以也一定程度上缓解了服务端的存储压力。但是有利也有弊,既然存储了用户信息(虽然进行加密)那么就有可能被窃取和利用,csrf(跨站伪造请求)攻击就利用了这一点。
失效时间
默认的cookie失效时间是 1209600秒 (2个星期,以秒数为单位),也就是说如果在用户登陆页面你勾选了‘记住密码’选项,那么两周之内,当再次访问该网站时,就无需再进行身份验证,cookie就像是网站颁发给你的一张会失效的通行证。当然如果你没有勾选,cookie信息只保存在浏览器内存中,当你关闭浏览器,再次访问该网站就需要乖乖的再次进行用户验证登陆了。
另外由于cookie是保存在本地客户端的电脑上,所以javascript也可以操作cookie。
demo
下面来看一下在django的demo:
在路由系统下:
from django.conf.urls import url urlpatterns = [ url(r'^cookieTest/', views.cookieTest), ]
视图函数下:
from django.shortcuts import HttpResponse def cookieTest(request): response = HttpResponse()#建立一个HttpResponse对象 response.set_cookie('binggan', 'cookie')#设置一个cookie值 return response
让我们来看一下浏览器下的
对应的url:
在第一次请求的时候,服务端返回一个response headers包含binggan=cookie
在浏览器的存储格式为{‘binggan’: ‘cookie’}
但改变试图函数,也就是第二次发送请求的时候,这是本地已经有服务端颁发的cookie
试图函数如下:
from django.shortcuts import render, HttpResponse def cookieTest(request): response = HttpResponse() if request.COOKIES.get('binggan'):#判断是否有此cookie cookie = request.COOKIES response.write(cookie['binggan'])#如果有则写入 return response
浏览器:
浏览器正确返回cookie值。
可以看到在response headers中已经没有set-cookie,而在request header中的cookie中最后一行binggan=cookie
也就是说cookie值已经写入本地浏览器,在本次请求过程中已经发送给服务端。
session
上面我们说到http协议是无状态的,客户端与服务端的一次通信,就是一次会话,也就是当一次会话完成之后,第二次会话就仍旧需要验证信息,为了解决这个问题,也就是为了状态保持(目的是在一段时间内跟踪请求者的状态,可以实现跨页面访问当前请求者的数据),可以再客户端或者服务端存储相关的数据,与cookie不同的是,cookie技术是客户端的解决方案,而session技术是服务端的解决方案。
比较
cookie存储在本地浏览器,存在相应的风险,所以一般避免存储敏感信息,而session存储在服务端,Session的安全性和可靠程度都比Cookie高,但这也相应的增加了服务器的存储压力。
依赖关系
如果说cookie是服务端颁发给用户的一张通行证的话,每次用户访问网站就会凭借这张通行证进入,那么session就像是用户的一张具体信息记录表,记录着每次用户的登录即其相关信息,当用户访问服务端的时候直接凭借通行证就可以查询记录表。所以可以看出session是依赖与cookie的,下面来详细说一下为什么是这样的依赖关系。
session生成
首先session何时创建的呢,这取决于服务端程序的运行。当服务端创建了session的同时,服务器会为该session生成一个唯一的session id,这个id通常是一个随机的字符串,并且在创建之后通过response headers送给浏览器,写入浏览器cookie,这个id会在随后的浏览器request headers请求中的cookie发送给服务器,找到在服务器已经创建的session,并相应的往session中增加内容。这也就是为什么禁用Cookie就不能得到Session呢?因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于失去了Session ID,也就得不到Session了。
session的生命周期:
为了保证存取速度,session一般保存在服务器内存中,每一个用户根据cookie和session id都有一个独立的session,另外session在服务器的存储也是以键值对的方式存储的,所以考虑到高并发的情况,session应该尽量精简,Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
有效期
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间没有活动的Session从服务器内存中清除,此时Session便失效。
该Cookie为服务器自动生成的,它的maxAge属性一般为-1,表示仅当前浏览器内有效,并且各浏览器窗口间不共享,关闭浏览器就会失效。因此同一机器的两个浏览器窗口访问服务器时,会生成两个不同的Session。但是如果是同一浏览器的不同子窗口访问,这类子窗口会共享父窗口的Cookie,因此会共享一个Session。
注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在链接上右击,在弹出的快捷菜单中选择"在新窗口中打开"时,子窗口便可以访问父窗口的Session。
三种存储
django中session的三种存储方法:放在数据库、缓存,文件系统,基于cookie的session。
在Django中Session是通过一个中间件管理的。如果要在应用程序中使用Session,需要在settings.py中的MIDDLEWARE_CLASSES变量中加入’django.contrib.sessions.middleware.SessionMiddleware’ 。
1. 将Session存储在数据库中:
在django中是默认支持session的并且会将session存储到数据库中,即django_session表中。
如果要将Session存储在数据库中,我们需要将 ’django.contrib.sessions’ 加入到INSTALLED_APPS 变量中。然后运行 manage.py syncdb 在数据库中创建相应的存储Session的数据库表。
2. 将Session存储在缓存中:
如果想获得更好的性能,我们可以将Session保存在缓存中。这里有两种配置方式:
一种是设置SESSION_ENGINE 为”django.contrib.sessions.backends.cache” 。这是一种简单配置,Session将之被保存在缓存中,但是不保证Session总是能取到(比如缓存溢出时Session会丢失);
另一种方式是设置SESSION_ENGINE 为 “django.contrib.sessions.backends.cached_db”。这种方式下,Session在保存到缓存的同时还会被保存到数据库中,当Django在缓存中找不到Session时,会从数据库中找到。第二种方式会有一点点性能开销,但是安全性和冗余性更好。
两种会话的存储都非常快,但是简单的缓存更快,因为它放弃了持久性。大部分情况下, cached_db 已经足够快,但是如果你需要榨干最后一点的性能,并且接收让会话数据丢失,那么你可使用 cache 。
3. 将Session存储在文件系统中:
将Session存储在文件系统中。需要设置SESSION_ENGINE 为”django.contrib.sessions.backends.file”,这时你还需要同时设置SESSION_FILE_PATH 变量,它代表Session文件保存的位置,缺省的设置一般是tempfile.gettempdir(),表示系统的临时目录。这里要确保应用程序对那个目录有读写的权限。
4, 使用基于cookie的session:
要使用基于cookie的session,需要将SESSION_ENGINE设置为“django.contrib.session.backends.signed_cookies”,此时,会话数据,的存储将使用django的加密签名工具和SECRET_KEY设置。