Cookie的工作原理和应用详解
1. Cookie 原理
1.1 Cookie 背景信息
客户端状态管理技术,将状态信息保存在客户端。
网景公司发明,浏览器会话技术
。
一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称name
和设置值value
。
浏览器一般只允许存放300
个Cookie,每个站点最多存放20
个Cookie,每个大小限制为4kb
。
1.2 Cookie 工作原理
执行流程:
- 浏览器向服务器发送请求,服务器需要创建cookie,服务器会通过响应携带cookie,在产生响应时会产生Set-Cookie响应头,从而将cookie信息传递给了浏览器;
- 当浏览器再次向服务器发送请求时,会产生cookie请求头,将之前服务器的cookie信息再次发送给了服务器,然后服务器根据cookie信息跟踪客户端状态。
1.3 Cookie 创建、获取、修改
chrome谷歌浏览器查看cookie信息,浏览器地址栏输入:
- chrome://settings/content/cookies
- chrome://settings/siteData
Cookie 创建:
// 用响应创建Cookie,等价于 response.addHeader("set-cookie", "name=value");
Cookie cookie=newCookie(String name, String value);// Cookie: name=value
cookie.setMaxAge(seconds);// 设置Cookie的生命周期
cookie.setPath("/");// 设置Cookie的共享范围
response.addCookie(cookie);// 添加1个Cookie
Cookie 获取:
// 用请求获取Cookie
Cookie[] cookies= request.getCookies();// 获取Cookies返回数组// 需遍历
cookie.getName();// 获取键
cookie.getValue();// 获取值
Cookie 修改:
// 修改Cookie
cookie.setValue(String name);
1.4 Cookie 共享范围
/
当前项目下所有资源
均可共享访问该Cookie对象内容/project/demo
当前项目下只有资源demo
均可共享访问该Cookie对象内容
设置 Cookie 数据共享范围:
// 设置Cookie的共享范围
cookie.setPath("/");
1.5 Cookie 生命周期
- <0:浏览器会话结束/浏览器关闭,内存存储(
默认
) - =0:失效
- >0:生效时间,单位s
在生命周期内Cookie会跟随任何请求,可通过
设置路径限制携带Cookie的请求资源范围
。
设置 Cookie 数据生命周期:
// 设置Cookie生命周期,单位s
cookie.setMaxAge(int second);// 7天:7*24*60*60
1.6 Cookie 中文乱码 - 解决方案
中文:Unicode,4个字节 英文:ASCII,2个字节
Cookie的中文乱码需要进行编码和解码处理:
编码:java.net.URLEncoder 的URLEncoder.encode(String str, String encoding)
解码:java.net.URLDecoder 的URLDecoder.decode(String str, String encoding)
// 编码
Cookie cookie=newCookie(
URLEncoder.encode("键","utf-8"),
URLEncoder.encode("值","utf-8"));
response.addCookie(cookie);// 解码
String keyStr= URLDecoder.decode(cookie.getName(),"utf-8");
1.7 Cookie 优缺特点分析
优点:
●可配置到期规则
:① 1次请求就失效 ②1次浏览器会话(关闭)失效 ③配置永久生效
●简单性
:基于文本的轻量结构,简单键值对
●数据持久性
:虽然Cookie可被客户端浏览器的过期处理和干预,但Cookie通常也是客户端上持续时间最长的数据保留形式
缺点:
●大小受到限制
:大多数浏览器的Cookie只有4kb大小的限制
●用户配置禁用
:客户浏览器设置了禁用接收Cookie的能力,限制了该功能
●潜在安全风险
:用户可能会操纵篡改浏览器上的Cookie,会造成Cookie应用程序执行失败的问题
2. Cookie 应用
2.0 工具类:CookieUtils
publicclassCookieUtils{/**
* 获取指定名称的Cookie对象
* @param cookies 一组Cookie
* @param cookieName 指定的Cookie名称
* @return 需要的Cookie
*/publicstatic CookiegetCookie(Cookie[] cookies, String cookieName){if(null!= cookies&&0!= cookies.length){for(Cookie ck: cookies){if(cookieName.equals(ck.getName())){return ck;}}}return null;}}
2.1 案例:记录用户上一次访问时间
核心逻辑:
// 判断是否是第一次请求
Cookie cookie= CookieUtils.getCookie(request.getCookies(),"lastTime");
SimpleDateFormat sdf=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");if(null== cookie){// 第一次访问,打印当前时间,并创建Cookie,存储当前时间
Date date=newDate();
System.out.println("第一次访问时间:"+ sdf.format(date));
cookie=newCookie("lastTime", String.valueOf(date.getTime()));}else{// 不是第一次访问,从cookie去除上一次访问时间,并打印,获取当前时间,存储cookie中long currTimeMills= Long.parseLong(cookie.getValue());
System.out.println("上一次访问时间:"+ sdf.format(newDate(currTimeMills)));
cookie.setValue(String.valueOf((newDate()).getTime()));}
response.addCookie(cookie);
2.2 案例:记录商品的浏览历史信息
历史记录核心逻辑:
String id= request.getParameter("id");
Cookie cookie= CookieUtils.getCookie(request.getCookies(),"history");if(null== cookie){// 木有浏览记录:创建Cookie,并存储浏览记录
cookie=newCookie("history", id);}else{// 有浏览记录
String history= cookie.getValue();if(!history.contains(id)){// 有浏览记录,不包含当前浏览商品:将浏览商品拼接到已有的浏览记录中
history+="-"+ id;
cookie.setValue(history);}// 有浏览记录,包含当前浏览商品则无需处理}
response.addCookie(cookie);// 显示商品浏览记录,路径:/demo/show
response.sendRedirect(request.getContextPath()+ File.separator+"show");
显示历史记录信息:
// 获取商品浏览记录
Cookie cookie= CookieUtils.getCookie(request.getCookies(),"history");
StringBuffer respsb=newStringBuffer();if(null== cookie){// 没有浏览记录
respsb.append("<font color='red'>没有浏览记录</font>,");
respsb.append("<a href='books.html'>浏览商品</a>");}else{// 有浏览记录: 0-1-2-3
String[] books={"西游记","红楼梦","水浒传","三国志"};
String history= cookie.getValue();
String[] historys= history.split("-");
respsb.append("您的浏览记录如下:<br>");for(String index: historys){
String bookName= books[Integer.parseInt(index)];
respsb.append(bookName).append("<br>");}}
response.setContentType("text/html;charset=utf-8");
response.getWriter().println(respsb);
点击第一个后: