目录
一.介绍
Cookie 对象与 HttpSession 对象的作用是维护客户端浏览器与服务端的会话状态的两个对象。由于 HTTP 协议是一个无状态的协议,所 以服务端并不会记录当前客户端浏览器的访问状态,但是在有些时 候我们是需要服务端能够记录客户端浏览器的访问状态的,如获取 当前客户端浏览器的访问服务端的次数时就需要会话状态的维持。
在 Servlet 中提供了 Cookie 对象与 HttpSession 对象用于维护客户端 与服务端的会话状态的维持。二者不同的是 Cookie 是通过客户端浏 览器实现会话的维持,而 HttpSession 是通过服务端来实现会话状态 的维持。
二.Cookie对象的特点
- Cookie使用字符串存储数据
- Cookie使用Key与Value结构存储数据
- 单个Cookie存储数据大小限制在4097个字节
- Cookie存储的数据中Servlet4.0之前不支持中文,Servlet4.0中支持
- Cookie是与域名绑定所以不支持跨一级域名访问
- Cookie对象保存在客户端浏览器内存或系统磁盘中
- Cookie分为持久化Cooke(放在系统磁盘中)与状态Cookie (放在客户端浏览器内存)
- 浏览器在保存同一域名所返回Cookie的数量是有限的。不同浏览器支持的数量不同,Chrome浏览器为50个
- 浏览器每次请求时都会把与当前访问的域名相关的所有Cookie在请求中提交到服务端。
三.Cookie对象的创建
注意Cookie是服务器端创建并返回给用户的。
Cookie cookie = new Cookie("key","value")
通过 new 关键字创建 Cookie 对象
response.addCookie(cookie)
通过 HttpServletResponse 对象将 Cookie 写回给客户端浏览器。
CreateCookieServlet.java:
package com.first.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class CreateCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie=new Cookie("key","流连忘返");
//将Cookie写回给客户端浏览器
resp.addCookie(cookie);
PrintWriter pw=resp.getWriter();
pw.println("create cookie ok");
pw.flush();
pw.close();
}
}
配置web.xml:
<servlet>
<servlet-name>CreateCookieServlet</servlet-name>
<servlet-class>com.first.servlet.CreateCookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CreateCookieServlet</servlet-name>
<url-pattern>/cookie.do</url-pattern>
</servlet-mapping>
输出:
先按F12,再访问此servlet
点击Application-->Cookie
四.获取Cookie中的数据
浏览器每次请求时都会把与当前访问的域名相关的 Cookie 在请求中提交到服务端。通过 HttpServletRequest 对象获取 Cookie ,返回 Cookie 数组。
Cookie[] cookies = request.getCookies();
上节运行的浏览器不要关(服务器也别关,因为实际生活中服务器就是一直运行),因为我们现在使用的是状态cookie(会保存到当前浏览器中),浏览器一关cookie就被清空了。
GetCookieDataServlet.java:
package com.first.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class GetCookieDataServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从客户端获取Cookie对象
Cookie[] cookies=req.getCookies();
//获取Cookie中的数据
PrintWriter pw=resp.getWriter();
for (int i=0;i<cookies.length;i++){
Cookie cookie=cookies[i];
String name=cookie.getName();
String value=cookie.getValue();
pw.println("Name: "+name+" Value: "+value);
}
pw.flush();
pw.close();
}
}
配置web.xml:
<servlet>
<servlet-name>GetCookieDataServlet</servlet-name>
<servlet-class>com.first.servlet.GetCookieDataServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetCookieDataServlet</servlet-name>
<url-pattern>/getCookie.do</url-pattern>
</servlet-mapping>
输出:
五.解决Cookie不支持中文
在 Cookie 中 name 的值不能使用中文, Value 是可以的。但是在Servlet4.0 版本之前 Cookie 中的 Value 也是不支持中文存储的,如果 存储的数据中含有中文,代码会直接出现异常。我们可以通过对含 有中文的数据重新进行编码来解决该问题。在 Servlet4.0 中的 Cookie 的 Value 开始支持中文存储。
报的异常:
java.lang.IllegalArgumentException: Control character in cookie value or attribute.
还是建议做如下处理,因为这样普适性较高,不用担心版本问题。
URLEncoder.encode("content","code")
将内容按照指定的编码方式做 URL 编码处理。
URLDecoder.decode("content","code")
将内容按照指定的编码方式做 URL 解码处理。
上面的两个例子稍加修改:
CreateCookieServlet.java:
//创建Cookie对象
Cookie cookie=new Cookie(URLEncoder.encode("回头看","utf-8"),
URLEncoder.encode("流连忘返","utf-8"));
GetCookieDataServlet.java:
pw.println("Name: "+ URLDecoder.decode(name,"utf-8")
+" Value: "+URLDecoder.decode(value,"utf-8"));
输出:
六.Cookie跨域问题
域名分类:域名分为顶级域、顶级域名(一级域名)、二级域名。
域名等级的区别:一级域名比二级域名更高级,二级域名是依附于一级域名之下的附属分区域名,即二级域名是一级域名的细化分 级。例如: baidu.com 为一级域名, news.baidu.com 为二级域 名。
Cookie不支持一级域名的跨域,支持二级域名的跨域。一级域名(即顶级域名)需要申请,二级域名不需要申请,二级域名自己扩展即可。
七.状态Cookie与持久化Cookie
状态 Cookie : Cookie 对象仅会被缓存在浏览器所在的内存中。当浏览器关闭后 Cookie 对象 也会被销毁。
持久化 Cookie :浏览器会对 Cookie 做持久化处理,基于文件形式保存在系统的指定目录中。在 Windows10 系统中为了安全问题不会显 示 Cookie 中的内容。
当 Cookie 对象创建后默认为状态 Cookie 。可以使用 Cookie 对象下的cookie.setMaxAge(60) 方法设置失效时间,单位为秒。一旦设置了 失效时间,那么该 Cookie 为持久化 Cookie ,浏览器会将 Cookie 对象 持久化到磁盘中。当失效时间到达后文件删除。
//创建Cookie对象
Cookie cookie=new Cookie(URLEncoder.encode("回头看","utf-8"),
URLEncoder.encode("流连忘返","utf-8"));
//变为持久化cookie,生存时间是120s,在生存时间内关闭浏览器没问题
cookie.setMaxAge(120);
八.通过Cookie实现客户端与服务端会话的维持
需求:当客户端浏览器第一次访问 Servlet 时响应 “ 您好,欢迎您第一次访问! ” ,第二次访问时响应 “ 欢迎您回来! ” 。
WelcomeServlet.java:
package com.first.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class WelcomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] cookies=req.getCookies();
//有无标志访问的Cookie
boolean flag=false;
if (cookies!=null){
for (Cookie cookie:cookies){
if ("welcome".equals(cookie.getName())){
//不是第一次访问
flag=true;
break;
}
}
}
resp.setContentType("text/plain;charset=utf-8");
PrintWriter pw=resp.getWriter();
if (flag){
pw.println("欢迎您回来!");
}else {
pw.println("您好,欢迎您第一次访问!");
Cookie cookie=new Cookie("welcome","welcome");
cookie.setMaxAge(60);
//把这个cookie响应给用户
resp.addCookie(cookie);
}
}
}
web.xml配置:
<servlet>
<servlet-name>WelcomeServlet</servlet-name>
<servlet-class>com.first.servlet.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WelcomeServlet</servlet-name>
<url-pattern>/welcome.do</url-pattern>
</servlet-mapping>
输出:
刷新一下
Cookie 总结
Cookie 对于存储内容是基于明文的方式存储的,所以安全性很低。 win10做了改进,不再让用户直接看到明文。
不要在 Cookie 中存放敏感数据。在数据存储时,虽然在 Servlet4.0 中 Cookie 支持中文,但是建议对 Cookie 中存放的内容做编码处理, 也可提高安全性。