Cookie/Session机制详解

会话跟踪是Web程序中经常使用技术,用来跟踪用户的整个会话。经常使用的会话跟踪技术是cookie与session。cookie经过客户端肯定记录信息肯定用户身份,session经过服务器端记录信息肯定用户身份。java

三者的异同

特性 Cookie localStorage sessionStorage
数据的生命期 通常由服务器生成,可设置失效时间。若是在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清除,不然永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小 4K左右 通常为5MB
与服务器端通讯 每次都会携带在HTTP头中,若是使用cookie保存过多数据会带来性能问题 仅在客户端(即浏览器)中保存,不参与和服务器的通讯
易用性 须要程序员本身封装,源生的Cookie接口不友好 源生接口能够接受,亦可再次封装来对Object和Array有更好的支持

 

1.cookie机制jquery

理论上,一个用户的全部操做请求都应该属于同一个会话,而另外一个用户的全部请求操做则应该属于另外一个会话。程序员

而web应用程序是使用http协议传输数据的。http是无状态的协议。一旦数据交换完毕,客户端与服务端的链接就会关闭,再次交换数据须要从新创建链接。这意味着服务器没法跟踪会话。即永华A购买了一件商品放入购物车内,当再次购买商品时,服务器已经没法判断该购买行为属于用户A仍是用户B的会话了,要想跟踪会话,必须引入一种机制。web

1.1 什么是cookie数据库

因为http是无状态协议,服务器单从网络链接上无从得知客户身份,就给客户端颁发一个通行证吧,每人一个,不管访问什么都必须携带本身的通行证。这样服务器就能从通行证确认客户身份了。这就是cookie的工做原理。编程

查看一个网站的cookie很简单,在浏览器控制台输入alert(document.cookie)就能够了。跨域

1.2 记录永华访问次数数组

经过request.getCookie()获取客户端提交的全部Cookie(以Cookie[]数组形式返回),经过response.addCookie(Cookiecookie)向客户端设置Cookie。浏览器

Cookie对象使用key-value属性对的形式保存用户状态,一个Cookie对象保存一个属性对,一个request或者response同时使用多个Cookie。安全

1.3 cookie不可跨域名

Cookie具备不可跨域名性根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操做Google的Cookie,而不能操做Baidu的Cookie。须要注意的是,虽然网站images.google.com与网站www.google.com同属于Google,可是域名不同,两者一样不能互相操做彼此的Cookie。注意:用户登陆网站www.google.com以后会发现访问images.google.com时登陆信息仍然有效,而普通的Cookie是作不到的。这是由于Google作了特殊处理。本章后面也会对Cookie作相似的处理。

1.4  Unicode编码:保存中文

中文与英文字符不一样,中文属于Unicode字符,在内存中占4个字符,而英文属于ASCII字符,内存中只占2个字节。Cookie中使用Unicode字符时须要对Unicode字符进行编码,不然会乱码。 

提示:Cookie中保存中文只能编码。通常使用UTF-8编码便可。不推荐使用GBK等中文编码,由于浏览器不必定支持,并且JavaScript也不支持GBK编码。

1.5  BASE64编码:保存二进制图片

Cookie不只可使用ASCII字符与Unicode字符,还可使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据时也须要进行编码。

%注意:本程序仅用于展现Cookie中能够存储二进制内容,并不实用。因为浏览器每次请求服务器都会携带Cookie,所以Cookie内容不宜过多,不然影响速度。Cookie的内容应该少而精。

1.6  设置Cookie的全部属性

先在浏览器中看一下cookie包含哪些内容:

除了name与value以外,Cookie还具备其余几个经常使用的属性。每一个属性对应一个getter方法与一个setter方法。Cookie类的全部属性如表1.1所示。

表1.1  Cookie经常使用属性

属  性  名 

描    述

String name

该Cookie的名称。Cookie一旦建立,名称便不可更改

Object value

该Cookie的值。若是值为Unicode字符,须要为字符编码。若是值为二进制数据,则须要使用BASE64编码

int maxAge

该Cookie失效的时间,单位秒。若是为正数,则该Cookie在maxAge秒以后失效。若是为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。若是为0,表示删除该Cookie。默认为–1

boolean secure

该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据以前先将数据加密。默认为false

String path

该Cookie的使用路径。若是设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序能够访问该Cookie。若是设置为“/”,则本域名下contextPath均可以访问该Cookie。注意最后一个字符必须为“/”

String domain

能够访问该Cookie的域名。若是设置为“.google.com”,则全部以“google.com”结尾的域名均可以访问该Cookie。注意第一个字符必须为“.”

String comment

该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明

int version

该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

设置一个有效期为 7 天的 cookie:

$.cookie('the_cookie', 'the_value', {expires: 7});

注:$.cookie 第三个参数是一个对象,除了能够设置有效期(expires: 7),还能够设置有效路径(path: '/')、有效域(domain: 'jquery.com')及安全性(secure: true)。

读取 cookie:

$.cookie('the_cookie'); 

注:若是没有该 cookie,返回 null。

删除 cookie:

$.cookie('the_cookie', null);

咱们只须要给须要删除的 cookie 设置为 null,就能够删除该 cookie。

1.7  Cookie的有效期

Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中经过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。

若是maxAge属性为正数,则表示该Cookie会在maxAge秒以后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。不管客户关闭了浏览器仍是电脑,只要还在maxAge秒以前,登陆网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效

 

Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(Integer.MAX_VALUE);           // 设置生命周期为MAX_VALUE

response.addCookie(cookie);                    // 输出到客户端

 

若是maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,所以关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。

若是maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,所以经过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,

 

例如:

Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(0);                          // 设置生命周期为0,不能为负数

response.addCookie(cookie);                    // 必须执行这一句

 

response对象提供的Cookie操做方法只有一个添加操做add(Cookie cookie)。

要想修改Cookie只能使用一个同名的Cookie来覆盖原来的Cookie,达到修改的目的。删除时只须要把maxAge修改成0便可。

 

注意:从客户端读取Cookie时,包括maxAge在内的其余属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。maxAge属性只被浏览器用来判断Cookie是否过时。

 

1.8  Cookie的修改、删除

Cookie并不提供修改、删除操做。若是要修改某个Cookie,只须要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。

若是要删除某个Cookie,只须要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。注意是0而不是负数。负数表明其余的意义。读者能够经过上例的程序进行验证,设置不一样的属性。

 

注意:修改、删除Cookie时,新建的Cookie除value、maxAge以外的全部属性,例如name、path、domain等,都要与原Cookie彻底同样。不然,浏览器将视为两个不一样的Cookie不予覆盖,致使修改、删除失败。

 

1.9  Cookie的域名

Cookie是不可跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制可以禁止网站非法获取其余网站的Cookie。

正常状况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,由于两者的域名并不严格相同。若是想全部helloweenvsfei.com名下的二级域名均可以使用该Cookie,须要设置Cookie的domain参数,例如:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie

cookie.setDomain(".helloweenvsfei.com");           // 设置域名

cookie.setPath("/");                              // 设置路径

cookie.setMaxAge(Integer.MAX_VALUE);               // 设置有效期

response.addCookie(cookie);                       // 输出到客户端

注意:domain参数必须以点(".")开始。另外,name相同但domain不一样的两个Cookie是两个不一样的Cookie。若是想要两个域名彻底不一样的网站共有Cookie,能够生成两个Cookie,domain属性分别为两个域名,输出到客户端。

 

1.10  Cookie的路径

domain属性决定运行访问Cookie的域名,而path属性决定容许访问Cookie的路径(ContextPath)。例如,若是只容许/sessionWeb/下的程序使用Cookie,能够这么写:

Cookie cookie = new Cookie("time","20080808");     // 新建Cookie

cookie.setPath("/session/");                          // 设置路径

response.addCookie(cookie);                           // 输出到客户端

设置为“/”时容许全部路径使用Cookie。path属性须要使用符号“/”结尾。name相同但domain相同的两个Cookie也是两个不一样的Cookie。

 

注意:页面只能获取它属于的Path的Cookie。例如/session/test/a.jsp不能获取到路径为/session/abc/的Cookie。使用时必定要注意。

 

1.11  Cookie的安全属性

HTTP协议不只是无状态的,并且是不安全的。使用HTTP协议的数据不通过任何加密就直接在网络上传播,有被截获的可能。使用HTTP协议传输很机密的内容是一种隐患。若是不但愿Cookie在HTTP等非安全协议中传输,能够设置Cookie的secure属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。下面的代码设置secure属性为true:

 

Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie

cookie.setSecure(true);                           // 设置安全属性

response.addCookie(cookie);                        // 输出到客户端

 

提示:secure属性并不能对Cookie内容加密,于是不能保证绝对的安全性。若是须要高安全性,须要在程序中对Cookie内容加密、解密,以防泄密。

 

1.12  JavaScript操做Cookie

Cookie是保存在浏览器端的,所以浏览器具备操做Cookie的先决条件。浏览器可使用脚本程序如JavaScript或者VBScript等操做Cookie。这里以JavaScript为例介绍经常使用的Cookie操做。例以下面的代码会输出本页面全部的Cookie。

<script>document.write(document.cookie);</script>

因为JavaScript可以任意地读写Cookie,有些好事者便想使用JavaScript程序去窥探用户在其余网站的Cookie。不过这是徒劳的,W3C组织早就意识到JavaScript对Cookie的读写所带来的安全隐患并加以防备了,W3C标准的浏览器会阻止JavaScript读写任何不属于本身网站的Cookie。换句话说,A网站的JavaScript程序读写B网站的Cookie不会有任何结果。

 

1.13  永久登陆

若是用户是在本身家的电脑上上网,登陆时就能够记住他的登陆信息,下次访问时不须要再次登陆,直接访问便可。实现方法是把登陆信息如帐号、密码等保存在Cookie中,并控制Cookie的有效期,下次访问时再验证Cookie中的登陆信息便可。

保存登陆信息有多种方案。最直接的是把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,通常不把密码等重要信息保存到Cookie中

还有一种方案是把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。若是不但愿保存密码,还能够把登陆的时间戳保存到Cookie与数据库中,到时只验证用户名与登陆时间戳就能够了。

这几种方案验证帐号时都要查询数据库。

本例将采用另外一种方案,只在登陆时查询一次数据库,之后访问验证登陆信息时再也不查询数据库。实现方式是把帐号按照必定的规则加密后,连同帐号一块保存到Cookie中。下次访问时只须要判断帐号的加密规则是否正确便可

 

2. Session机制

除了使用Cookie,Web应用程序中还常用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制使用上比Cookie简单一些,相应的也增长了服务器的存储压力

2.1  什么是Session

Session是另外一种记录客户状态的机制,不一样的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只须要从该Session中查找该客户的状态就能够了。

若是说Cookie机制是经过检查客户身上的“通行证”来肯定客户身份的话,那么Session机制就是经过检查服务器上的“客户明细表”来确认客户身份。Session至关于程序在服务器上创建的一份客户档案,客户来访的时候只须要查询客户档案表就能够了。

2.2  实现用户登陆

Session对应的类为javax.servlet.http.HttpSession类。每一个来访者对应一个Session对象,全部该客户的状态信息都保存在这个Session对象里。Session对象是在客户端第一次请求服务器的时候建立的Session也是一种key-value的属性对,经过getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法读写客户状态信息。Servlet里经过request.getSession()方法获取该客户的Session,

例如:

HttpSession session = request.getSession();       // 获取Session对象

session.setAttribute("loginTime", new Date());     // 设置Session中的属性

   

out.println("登陆时间为:" +(Date)session.getAttribute("loginTime"));      // 获取Session属性

request还可使用getSession(boolean create)来获取Session。区别是若是该客户的Session不存在,request.getSession()方法会返回null,而getSession(true)会先建立Session再将Session返回。

Servlet中必须使用request来编程式获取HttpSession对象,而JSP中内置了Session隐藏对象,能够直接使用。若是使用声明了<%@page session="false" %>,则Session隐藏对象不可用。下面的例子使用Session记录客户帐号信息。

2.3  Session的生命周期

Session保存在服务器端。为了得到更高的存取速度,服务器通常把Session放在内存里。每一个用户都会有一个独立的Session。若是Session内容过于复杂,当大量客户访问服务器时可能会致使内存溢出。所以,Session里的信息应该尽可能精简。

Session在用户第一次访问服务器的时候自动建立。须要注意只有访问JSP、Servlet等程序时才会建立Session,只访问HTML、IMAGE等静态资源并不会建立Session。若是还没有生成Session,也可使用request.getSession(true)强制生成Session。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,不管是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

 

1.2.4  Session的有效期

因为会有愈来愈多的用户访问服务器,所以Session也会愈来愈多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。若是超过了超时时间没访问过服务器,Session就自动失效了。

Session的超时时间为maxInactiveInterval属性,能够经过对应的getMaxInactiveInterval()获取,经过setMaxInactiveInterval(longinterval)修改。

Session的超时时间也能够在web.xml中修改。另外,经过调用Session的invalidate()方法可使Session失效。

 

2.5  Session的经常使用方法

Session中包括各类方法,使用起来要比Cookie方便得多。Session的经常使用方法如表1.2所示。

表1.2  HttpSession的经常使用方法

方  法  名

描    述

void setAttribute(String attribute, Object value)

设置Session属性。value参数能够为任何Java Object。一般为Java Bean。value信息不宜过大

String getAttribute(String attribute)

返回Session属性

Enumeration getAttributeNames()

返回Session中存在的属性名

void removeAttribute(String attribute)

移除Session属性

String getId()

返回Session的ID。该ID由服务器自动建立,不会重复

long getCreationTime()

返回Session的建立日期。返回类型为long,常被转化为Date类型,例如:Date createTime = new Date(session.get CreationTime())

long getLastAccessedTime()

返回Session的最后活跃时间。返回类型为long

int getMaxInactiveInterval()

返回Session的超时时间。单位为秒。超过该时间没有访问,服务器认为该Session失效

void setMaxInactiveInterval(int second)

设置Session的超时时间。单位为秒

void putValue(String attribute, Object value)

不推荐的方法。已经被setAttribute(String attribute, Object Value)替代

Object getValue(String attribute)

不被推荐的方法。已经被getAttribute(String attr)替代

boolean isNew()

返回该Session是不是新建立的

void invalidate()

使该Session失效

Tomcat中Session的默认超时时间为20分钟。经过setMaxInactiveInterval(int seconds)修改超时时间。能够修改web.xml改变Session的默认超时时间。例如修改成60分钟:

<session-config>

   <session-timeout>60</session-timeout>      <!-- 单位:分钟 -->

</session-config>

 

注意:<session-timeout>参数的单位为分钟,而setMaxInactiveInterval(int s)单位为秒。

 

2.6  Session对浏览器的要求

虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然须要客户端浏览器的支持。这是由于Session须要使用Cookie做为识别标志。HTTP协议是无状态的,Session不能依据HTTP链接来判断是否为同一客户,所以服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。

该Cookie为服务器自动生成的,它的maxAge属性通常为–1,表示仅当前浏览器内有效,而且各浏览器窗口间不共享,关闭浏览器就会失效。

所以同一机器的两个浏览器窗口访问服务器时,会生成两个不一样的Session。可是由浏览器窗口内的连接、脚本等打开的新窗口(也就是说不是双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的Cookie,所以会共享一个Session。

 

注意:新开的浏览器窗口会生成新的Session,但子窗口除外。子窗口会共用父窗口的Session。例如,在连接上右击,在弹出的快捷菜单中选择“在新窗口中打开”时,子窗口即可以访问父窗口的Session。

若是客户端浏览器将Cookie功能禁用,或者不支持Cookie怎么办?例如,绝大多数的手机浏览器都不支持Cookie。Java Web提供了另外一种解决方案:URL地址重写。

 

2.7  URL地址重写

URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器可以解析重写后的URL获取Session的id。这样即便客户端不支持Cookie,也可使用Session来记录用户状态。HttpServletResponse类提供了encodeURL(Stringurl)实现URL地址重写,例如:

<td>

    <a href="<%=response.encodeURL("index.jsp?c=1&wd=Java") %>"> 
    Homepage</a>

</td>

该方法会自动判断客户端是否支持Cookie。若是客户端支持Cookie,会将URL原封不动地输出来。若是客户端不支持Cookie,则会将用户Session的id重写到URL中。重写后的输出多是这样的:

<td>

    <ahref="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=
    1&wd=Java">Homepage</a>

</td>

即在文件名的后面,在URL参数的前面添加了字符串“;jsessionid=XXX”。其中XXX为Session的id。分析一下能够知道,增添的jsessionid字符串既不会影响请求的文件名,也不会影响提交的地址栏参数。用户单击这个连接的时候会把Session的id经过URL提交到服务器上,服务器经过解析URL地址得到Session的id。

若是是页面重定向(Redirection),URL地址重写能够这样写:

<%

    if(“administrator”.equals(userName))

    {

       response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));

        return;

    }

%>

效果跟response.encodeURL(String url)是同样的:若是客户端支持Cookie,生成原URL地址,若是不支持Cookie,传回重写后的带有jsessionid字符串的地址。

对于WAP程序,因为大部分的手机浏览器都不支持Cookie,WAP程序都会采用URL地址重写来跟踪用户会话。好比用友集团的移动商街等。

 

注意:TOMCAT判断客户端浏览器是否支持Cookie的依据是请求中是否含有Cookie。尽管客户端可能会支持Cookie,可是因为第一次请求时不会携带任何Cookie(由于并没有任何Cookie能够携带),URL地址重写后的地址中仍然会带有jsessionid。当第二次访问时服务器已经在浏览器中写入Cookie了,所以URL地址重写后的地址中就不会带有jsessionid了。

 

2.8  Session中禁止使用Cookie

既然WAP上大部分的客户浏览器都不支持Cookie,索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持经过配置的方式禁用Cookie。下面举例说一下怎样经过配置禁止使用Cookie。

打开项目sessionWeb的WebRoot目录下的META-INF文件夹(跟WEB-INF文件夹同级,若是没有则建立),打开context.xml(若是没有则建立),编辑内容以下:

代码1.11 /META-INF/context.xml

<?xml version='1.0' encoding='UTF-8'?>

<Context path="/sessionWeb"cookies="false">

</Context>

 

或者修改Tomcat全局的conf/context.xml,修改内容以下:

代码1.12  context.xml

<!-- The contents of this file will be loaded for eachweb application -->

<Context cookies="false">

    <!-- ... 中间代码略 -->

</Context>

部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了。 

注意:该配置只是禁止Session使用Cookie做为识别标志,并不能阻止其余的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,可是程序中仍然能够读写其余的Cookie。

应用场景

有了对上面这些差异的直观理解,咱们就能够讨论三者的应用场景了。

由于考虑到每一个 HTTP 请求都会带着 Cookie 的信息,因此 Cookie 固然是能精简就精简啦,比较经常使用的一个应用场景就是判断用户是否登陆。针对登陆过的用户,服务器端会在他登陆时往 Cookie 中插入一段加密过的惟一辨识单一用户的辨识码,下次只要读取这个值就能够判断当前用户是否登陆啦。曾经还使用 Cookie 来保存用户在电商网站的购物车信息,现在有了 localStorage,彷佛在这个方面也能够给 Cookie 放个假了~

而另外一方面 localStorage 接替了 Cookie 管理购物车的工做,同时也能胜任其余一些工做。好比HTML5游戏一般会产生一些本地数据,localStorage 也是很是适用的。若是遇到一些内容特别多的表单,为了优化用户体验,咱们可能要把表单页面拆分红多个子页面,而后按步骤引导用户填写。这时候 sessionStorage 的做用就发挥出来了。

安全性的考虑

须要注意的是,不是什么数据都适合放在 Cookie、localStorage 和 sessionStorage 中的。使用它们的时候,须要时刻注意是否有代码存在 XSS 注入的风险。由于只要打开控制台,你就随意修改它们的值,也就是说若是你的网站中有 XSS 的风险,它们就能对你的 localStorage 肆意妄为。因此千万不要用它们存储你系统中的敏感数据。

相关文章
相关标签/搜索