cookie详解
cookie简介
1. 定义
cookie是由服务器发送给客户端(浏览器)的小量信息。
2. 作用
cookie是键值对形式存储的少量信息,那它有什么作用呢?
我们知道,平时上网时都是使用无状态的HTTP协议传输出数据,这意味着客户端与服务端在数据传送完成后就会中断连接。这时我们就需要一个一直保持会话连接的机制。在session出现前,cookie就完全充当了这种角色。也就是,cookie的小量信息能帮助我们跟踪会话。一般该信息记录用户身份。
当然cookie也常记录跟踪购物车的商品信息(如数量)、记录用户访问次数等。
3. 原理
客户端请求服务器时,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。而客户端浏览器会把Cookie保存起来。当浏览器再请求服务器时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器通过检查该Cookie来获取用户状态。
4.添加cookie示例
获取客户端的Cookie时,只能获取name与value属性,其它属性都不会被提交。
Cookie c = new Cookie("username","peter");// 新建一个Cookie对象 c.setMaxAge(24*60*60); // 设置过期时间1天,以秒为单位 如果不设置时间 默认在浏览器关闭的时候销毁cookie response.addCookie(c); // 保存cookie到客户端
5.删除cookie示例
删除某个Cookie时,只需要新建同名Cookie,设置过期时间为0,然后添加到response中覆盖原来的Cookie
Cookie cookie = new Cookie("username","peter");// 新建Cookie cookie.setMaxAge(0); // 设置生命周期为0,表示将要删除 response.addCookie(cookie); // 执行添加后就从response里删除了
6.修改cookie示例
修改某个Cookie时,只需要新建一个只有value属性不一样的同名Cookie,然后添加到response中覆盖原来的Cookie
Cookie cookie = new Cookie("username","joker");// 新建Cookie cookie.setMaxAge(24*60*60); // 设置生命周期 response.addCookie(cookie); // 执行添加后就从response里覆盖修改了
注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie而不会覆盖之前的Cookie,从而导致修改、删除失败。
Cookie类的各方法详解
Cookie类在javax.servlet.http.Cookie包中
set方法:
方法名 | 返回类型 | 说明 |
---|---|---|
setValue(String newValue) | void | 给当前cookie重新赋值 |
setComment(String purpose) | void | 对该cookie进行描述的信息(说明作用),浏览器显示cookie信息时能看到 |
setDomain(String pattern) | void |
符合该pattern(域名正则)的就可以访问该Cookie的域名。如果设置为“.google.com”, 则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.” |
setHttpOnly(boolean httpOnly) | void | 设为true后,只能通过http访问,javascript无法访问,还可防止xss读取cookie |
setMaxAge(int expiry) | void |
该Cookie失效时间,单位秒。如果为正数,则该Cookie在expiry秒之后失效。如果为负数,该Cookie为临时Cookie, 关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1 |
setPath(String uri) | void |
设置Cookie的使用路径。后面紧接着详解。如果设置为“/abc/”,则只有uri为“/abc”的程序可以访问该Cookie。 如果设置为“/”,则本域名下的uri都可以访问该Cookie。注意最后一个字符必须为”/” |
setSecure(boolean flag) | void |
是否使用安全传输协议。为true时,只有当是https请求连接时cookie才会发送给服务器端, 而http时不会,但是服务端还是可以发送给浏览端的。 |
get和其他方法:
getValue() | String | 获取当前cookie的值 |
getComment() | String | 获取当前cookie的描述信息 |
getDomain() | String | 获取当前cookie的域名 |
getMaxAge() | int | 获取当前时间的过期时间 |
getName() | String | 获取当前cookie的名称 |
getPath() | String | 获取到浏览器返回该cookie的服务器上的路径。 |
getVersion() | String | 获取当前cookie符合的协议版本。 |
getSecure() | boolean | 如果浏览器只在安全协议上发送cookie,那么返回true;如果浏览器可以使用任何协议发送cookie,则返回false。 |
clone() | Object | 覆盖了标准的java . lang . object。克隆方法返回一个cookie的副本。 |
如果cookie值为Unicode字符,需要为字符编码。如果cookie值为二进制数据,则需要使用BASE64编码
设置同一服务器内的cookie使用范围用setPath
c.setPath(“/”),使同一服务器内所有应用都可访问到该Cookie: 默认路径是访问的servlet或jsp的父目录
Cookie c = new Cookie("name","peter"); c.setMaxAge(24*60*60); c.setPath("/");//同一服务器内所有应用都可访问到该Cookie response.addCookie(c); //保存cookie到客户端
-
如果同一服务器内有两个应用web01和web02
当我们在web01里有c.setPath("/web02/");
时,该cookie就只能在web02下面能获取到,就连创建该cookie的web01也获取不到。 -
如果在web01里有
c.setPath("/web02/abc/");
时,则只能在web02/abc下面才能获得该cookie,即使在web02下面也不能获取到。
cookie的跨域
1.正常情况下Cookie不可跨域名,如域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。即使在同一个一级域名下的两个二级域名如www.abc.com和images.abc.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有abc.com名下的二级域名都可以使用该Cookie,则需要设置Cookie的domain参数为”.abc.com”,例如:
Cookie cookie = new Cookie("name","peter"); // 新建Cookie cookie.setDomain(".abc.com"); // 设置域名 cookie.setPath("/"); // 设置路径 cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期为永久 response.addCookie(cookie); // 输出到客户端
读者可以修改本机C:\WINDOWS\system32\drivers\etc下的hosts文件来配置多个临时域名,然后使用setCookie.jsp程序来设置跨域名Cookie验证domain属性。
注意:domain参数必须以点(“.”)开始。另外,name相同但domain不同的两个Cookie是两个不同的Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个name相同的Cookie,domain属性分别为两个域名。
2.若A服务器的域名为:adv.audiogroup.com,有应用名为:web01; B服务器的域名为:abc.com,有应用名为:web02。
在A服务器的web01应用下设置cookie如下:
Cookie cookie = new Cookie("name","peter"); // 新建Cookie cookie.setDomain(".abc.com"); // 设置域名 cookie.setPath("/"); // 设置路径 cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期为永久 response.addCookie(cookie); // 输出到客户端
这时,在B服务器下的web02应用和web01里都能取到上面的Cookie。
注:输入URL访问web02时,必须输入域名才能获取其它服务器共享给它的cookie,如:
输入http://images.abc.com:8080/web02,可以获取web01在客户端设置的cookie
输入:http://localhost:8080/web02则不可以获得cookie。
setPath()与setDomain()的区别?
setDomain()主要用来确定两个不同名称但后缀相同的网站地址是否能使用同一个Cookie。
例: www.abc.com和 bbs.abc.com只要有cookie.setDomain(".zjut.edu.cn");
就都能使用该cookie
setPath()主要用来确定地址里什么后缀下能够使用这个Cookie
归结起来就是:setDomain决定允许访问Cookie的域名,而setPath决定允许访问Cookie的路径(ContextPath)
获取用户请求里的cookie
Cookie[] cookie = request.getCookies();//获取的是请求里的所有cookie组成的数组 for(int i=0;i<cookie.length;i++){ if("name".equals(cookie[i].getName())){ System.out.println(cookie[i].getValue());//得到peter break; } }
解决cookie里中文乱码问题
Cookie中要保存中文只能编码。一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。
Cookie不仅可以使用ASCII字符与Unicode字符,还可以使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据时也需要进行编码(如用BASE64编码保存二进制图片)。由于浏览器每次请求都会带着Cookie,因此Cookie内容不宜过多,所以一般不会在Cookie中存储二进制的内容
JS操作Cookie
Cookie是保存在客户端的,所以浏览器可以使用脚本(JS)等操作Cookie。
<script language=javascript> //添加cookie function setCookie(name,value,time){ var date= new Date(); date.setDate(date.getDate()+time); document.cookie = name+"="+value+";expires="+date; } //获得cookie function getCookie(name){ var arr = document.cookie.split(";"); for(var i=0; i<arr.length; i++){ var arr2 = arr[i].split("="); if(arr2[0] == name){ return arr2[1]; } } return null; } //删除cookie function removeCookie(name){ setCookie(name,"",0) } </script>
W3C标准的浏览器会阻止JavaScript读写任何不属于自己网站的Cookie。即A网站的JavaScript代码里获取不到B网站的Cookie。
使用cookie记住密码
方案1:
直接把用户名与密码都保持到Cookie中,下次访问时检查Cookie中的用户名与密码,与数据库比较。这是一种比较危险的选择,一般不把密码等重要信息保存到Cookie中。
方案2:
把密码加密后保存到Cookie中,下次访问时解密并与数据库比较。这种方案略微安全一些。如果不希望保存密码,还可以把登录的时间戳保存到Cookie与数据库中,到时只验证用户名与登录时间戳就可以了。
方案3:
实现方式是把账号按照一定的规则(密钥)加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否相同即可。
加 密:
String userName = request.getParameter("userName");//获取用户名 Md5Hash psw = new Md5Hash(userName, "peter.com", 2);//以peter.com为密钥加密 //将用户名添加进cookie并发送给客户端 Cookie userCookie = new Cookie("userName",userName); userCookie.setMaxAge(7*24*60*60); response.addCookie(userCookie); //将密钥生成的密文加进cookie并发送给客户端 Cookie c = new Cookie("key",psw.toString()); c.setMaxAge(7*24*60*60); response.addCookie(c);
解密:
String usreName = null; String key = null; Cookie[] cookie = request.getCookies(); if(cookie !=null){ for(Cookie c:cookie){ // 遍历Cookie if("userName".equals(c.getName()) userName = c.getValue(); if("key".equals(c.getName()) key= cookie.getValue(); } } if(userName != null && key != null){ String secrect = new Md5Hash(userName, "peter.com", 2); if(key.equals(secrect )){//加密规则正确,说明已经登录 //... //....省略后续处理 } }
由上面可知,如果将密码加密后存进cookie后,当我们下次访问登录页时,密码框里的密码将不是用户真正的密码。