首先,Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态,也就是跟踪用户的整个会话。不同的是,Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
一、理解Cookie
1、Cookie为什么会出现?
2、Cookie的属性项
属性项 | 属性项介绍 |
---|---|
NAME=VALUE | 键值对,可以设置要保存的Key/Value,注意这里的NAME不能和其他属性项的名字一样 |
Expires | 过期时间,在设置的某个时间点后该Cookie就会失效,如expires=Wednesday,16-Nov-17 23:12:40 GMT |
Max-Age | 最大失效时间,表示在多少秒后失效 |
Domain | 生成该Cookie的域名,即可以访问该Cookie的域名 |
Path | 生成该Cookie的路径,即可以访问该Cookie的路径,设置为“/”,则本域名下contextPath都可以访问该Cookie,最后一个字符必须为“/” |
Secure | 如果设置了这个属性,那么只会在使用安全协议连接时才会回传该Cookie,安全协议有HTTPS,SSL等。默认为false。 |
Comment | 注释项,说明该Cookie有何用途 |
Version | 该Cookie的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范 |
Port | 该Cookie在什么端口下可以回传服务端,如果有多个端口,用逗号隔开 |
Discard | 是否在会话结束后丢弃该Cookie项,默认为false |
下面详细介绍Cookie的这些属性项:
2.1 Cookie的有效期
response对象提供的Cookie操作方法只有一个添加操作add(Cookie cookie)。要想修改Cookie只能使用一个同名的Cookie来覆盖原来的Cookie。
删除时只需要把maxAge修改为0即可。
注意:
(1)从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。
maxAge属性只被浏览器用来判断Cookie是否过期。
(2)修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,
浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
2.2 Cookie的域名
Cookie是不可跨域名的。域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setDomain(".helloweenvsfei.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,可以生成两个Cookie,domain属性分别为两个域名,输出到客户端。
正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数,例如:
2.3 Cookie的路径
domain属性决定运行访问Cookie的域名,而path属性决定允许访问Cookie的路径(ContextPath)。例如,如果只允许/session/下的程序使用Cookie,可以这么写:
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setPath("/session/"); // 设置路径
response.addCookie(cookie); // 输出到客户端
设置为“/”时允许所有路径使用Cookie。path属性需要使用符号“/”结尾。name相同但path不相同的两个Cookie也是两个不同的Cookie。注意:页面只能获取它属于的Path的Cookie。例如/session/test/a.jsp不能获取到路径为/session/abc/的Cookie。
2.4 Cookie的安全属性
cookie.setSecure(true); // 设置安全属性
response.addCookie(cookie); // 输出到客户端
3、Cookie的字符编码
3.1 Unicode编码:保存中文
中文与英文字符不同,中文属于Unicode字符,在内存中占4个字符,而英文属于ASCII字符,内存中只占2个字节。Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会乱码。
注意:Cookie中保存中文只能编码。一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。
3.2 BASE64编码:保存二进制文件
4、Cookie的压缩
//压缩
private void compressCookie(Cookie c,HttpServletResponse res){
try{
ByteArrayOutputStream bos = null;
bos = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(bos);
dos.write(c.getValue().getBytes());
dos.close();
System.out.println("before compress length:" + c.getValue().getBytes().length);
String compress = new sum.misc.BASE64Encoder().encode(bos.toByteArray());
res.addCookie(new Cookie("compress",compress));
System.out.println("after compress length:" + compress.getBytes().length);
}catch(IOException e){
e.printStackTrace();
}
}
//解压缩
private void unCompressCookie(Cookie c){
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] compress = new sun.misc.BASE64Decoder().decodeBuffer(new String(c.getValue().getBytes()));
ByteArrayInputStream bis = new ByteArrayInputStream(compress);
InflaterInputStream inflater = new InflaterInputStream(bis);
byte[] b = new byte[1024];
int count;
while((count = inflater.read(b)) >= 0){
out.write(b,0,count);
}
inflater.close();
System.out.println(out.toByteArray());
}catch(Exception e){
e.printStackTrace();
}
}
5、Cookie是如何工作的?
String getCookie(Cookie[] cookies,String key){
if(cookies != null){
for(Cookie cookie: cookies){
if(cookie.getName().equals(key))
return cookie.getValue();
}
}
return null;
}
@Override
public void doGet(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
Cookie[] cookies = request.getCookies();
String username = getCookie(cookies,"username");
String userAge = getCookie(cookies,"userAge");
if(username == null)
response.addCookie(new Cookie("username","aaa"));
if(userAge == null)
response.addCookie(new Cookie("userAge","17"));
response.getHeaders("Set-Cookie");
}
Cookie是如何加到HTTP的Header中的呢?如下图是Tomcat创建Set-Cookie响应头的时序图: