Cookie和Session
会话:从用户打开浏览器,访问一个web应用程序开始,多次点击、访问服务器上的资源,多次的请求和响应,直到关闭浏览器,这整个过程就是一个会话
我们知道Http是一个无状态的协议,服务器不会记录客户端的信息,不管第几次发送请求给服务器,它也不会认识你
为了可以让浏览器和服务器进行一些交互,保存住一些必要数据,在HttpServlet中,提供了两个用于保存会话中数据的两个对象,分别是Cookie和Session
会话实现的过程:
浏览器访问服务器资源,建立会话,产生一个会话对象(Session),并且为这个会话生成一个唯一的标识,服务器会把这个标识响应给浏览器,保存在浏览器中。下次浏览器请求服务器时会带上这个标识,此时服务器会根据这个标识查找对应的Session对象,如果找到,那么就是同一个会话,继续本次会话,如果没找到,此时会再创建一个新的会话,生成新的标识。
Cookie
Cookie浏览器端的会话技术,将服务器返回的小量数据保存在浏览器中。
应用场景
- 网站登录时的记住密码和自动登录,当我们清除浏览器中的Cookie时,可以发现访问网站时还需要重新登录该网站
- 保存一些上次登录时间、上次打开的网页等等
- 记录浏览的次数···
使用Cookie主要用来做客户端和服务器之间的状态的保持(保持一种交互的状态),对于安全性要求不高,不需要浏览器存储大量的数据
使用
发送Cookie
- 创建Cookie对象,直接new Cookie(String key,String value);
- 将Cookie数据保存到客户端,使用response对象的addCookie()方法
Cookie cookie = new Cookie("name","xiaoming");
resp.addCookie(cookie);
打开浏览器的开发者工具,访问该Servlet,查看该请求;
获取Cookie
- 获取浏览器请求中的Cookie,使用request对象的getCookies()方法
- 遍历获取所有Cookie的键值对信息
Cookie[] cookies = req.getCookies();
for (Cookie c : cookies){
String key = c.getName();//获取Cookie对象中的键
String value = c.getValue();//获取Cookie对象中的值
System.out.println(key+"="+value);
}
(获取Cookie的前提是浏览器存储了Cookie,如果浏览器禁用了Cookie,我们也就获得不到Cookie,会话也因此失效)
编码问题
Cookie传递的数据从Tomcat8开始支持中文,但是我们也不建议使用中文
需要使用中文的话,建议将中文进行编码,查看时在进行解码
API:
- URLEncode类:
- public static String encode(String s, String enc);将指定字符串s使用指定的规则enc进行编码
- URLDecode类:
- public static String decode(String s, String enc);将指定字符串s使用指定的规则enc进行解码
String encode = URLEncoder.encode("小明","utf-8");
Cookie cookie = new Cookie("name",encode);
resp.addCookie(cookie);
Cookie[] cookies = req.getCookies();
for (Cookie c : cookies){
String key = c.getName();
String value = URLDecoder.decode(c.getValue(),"utf-8");
System.out.println(key+"="+value);
}
配置Cookie
在发送请求时,Cookie会放在请求头中传给服务器,但是一个浏览器中保存着很多个网站的Cookie,总不能将所有的Cookie都发送过去,所以,每一个Cookie都有一个自己的有效路径,只有访问到这个Cookie的有效路径,那么请求头中才会携带响应的Cookie
在Cookie对象中,有几个方法可以对Cookie进行响应的配置
返回值 | 方法名 | 说明 |
---|---|---|
void | setPath(String url) | 设置Cookie的有效路径 |
void | setMaxAge(int expiry) | 设置Cookie的存活时间(秒) |
Cookie的有效路径
cookie.setPath();
Cookie的最大存活时间
cookie.setMaxAge(60);
删除已有的Cookie
将一个Cookie存活时间设置为0,就可以达到效果
创建一个新的Cookie,设置key和有效路径都要和需要删除的Cookie的key和有效路径相同,设置存活时间为0,覆盖旧的Cookie即可
Cookie cookie1 = new Cookie("name","xxx");
cookie1.setMaxAge(0);
resp.addCookie(cookie1);
示例:
获取上次访问时间
@WebServlet(value = {"/cookieTest"})
public class CookieDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
Cookie[] cookies = req.getCookies();
String lasttime = null;
for (int i=0;cookies!=null && i<cookies.length;i++){
if (cookies[i].getName().equals("lastDate")){
lasttime = URLDecoder.decode(cookies[i].getValue(),"utf-8");
out.print("您上次的访问时间是:"+lasttime);
break;
}
}
if (lasttime==null){
out.print("您是第一次访问本网站");
}
Date date = new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String strDate=simpleDateFormat.format(date);
Cookie cookie=new Cookie("lastDate", URLEncoder.encode(strDate,"utf-8"));
cookie.setMaxAge(60);
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Session
Session:服务器端的会话技术,它可以把同一用户与服务器多次请求响应的一些数据记录在服务器Session域中,时间该用户在本次会话中,可以随时获取Session域中的对象,满足多次请求响应之间进行数据传递和访问
- Session与Cookie是紧密相关的,Session的使用需要用户浏览器支持Cookie,如果浏览器不支持Cookie,或者禁用了Cookie,那么将不能使用Session
可以说这个JSESSIONID它代表了一个服务器上的一次会话的唯一标识的ID,浏览器每次的请求头Cookie中一直保存这一个JSESSIONID,就可以维持这一次会话
Session使用的场景:
- 保存用户登录后的一些信息、操作
- 这些数据可以在让用户在不同的页面使用
获取Session对象:
-
public HttpSession getSession();
- 调用此方法时,容器会先检查客户端先前送出的请求是否 有建立过HTTP会话: 如果没有:容器会新建一个会话,并赋予一个唯一的会话ID。 如果有:容器会根据客户请求中的会话ID找到相匹配的会话。
-
public HttpSession getSession(boolean flag) ;
- 此方法的flag是用来指定是否有必要创建一个 会话,如果flag为false,那么如果是第一次建立会话,则返回null,不会自动创建一个新的会话
HttpSession的常用方法:
返回值 | 方法名 | 说明 |
---|---|---|
boolean | isNew() | 判断是否为新建的会话 |
long | getCreationTime() | 获取该Session创建时间(毫秒值) |
String | getId() | 获取会话的ID |
long | getLastAccessedTime() | 获取上次访问此会话的时间 |
ServletContext | getServletContext() | 获取该会话所在的ServletContext对象 |
void | setAttribute(String var1, Object var2) | 将指定键和值存放到会话中 |
Object | getAttribute(String var1) | 获取会话中的指定值,根据键 |
void | removeAttribute(String var1) | 移除会话中的指定值,根据键 |
void | invalidate() | 结束会话 |
void | setMaxInactiveInterval(int var1) | 设置会话超时的时间 |
long | getMaxInactiveInterval() | 获取会话的超时时间 |
方法演示:
@WebServlet(urlPatterns = {"/session1"})
public class SessionDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
HttpSession session = req.getSession();
PrintWriter out = resp.getWriter();
if (session.isNew()){
out.print("这是一个新的会话"+session.getId()+"<br>");
}else {
out.print("这是一个已存在的会话"+session.getId()+"<br>");
}
//设置会话的存活时间(一小时,默认应该为半小时)
session.setMaxInactiveInterval(3600);
SimpleDateFormat dateFormat = new SimpleDateFormat();
out.print("会话的创建时间为:"+dateFormat.format(session.getCreationTime())+"<br>");
out.print("会话的上次访问时间为:"+session.getLastAccessedTime()+"<br>");
out.print("会话的最大存活时间为:"+session.getMaxInactiveInterval()+"<br>");
//结束会话
// session.invalidate();
}
}
URL重写
上面讲到Cookie不安全的问题,如果用户浏览器禁用了Cookie,那么我们就无法实现会话技术,这时,我们就要采用另一种方式来保存我们会话的标识,维持我们的会话
使用URL重写:
将会话ID添加到URL结尾后面,这样服务器可以根据请求URL后面的会话ID来匹配和用户之间相应的会话。
HttpServletResponse接口中提供了两个用于完成URL重写的方法
- String encodeURL(String url) 对超链接或form表单的action属性中设置的URL进行重写。
- String encodeRedirectURL(String url) 对要传递给sendRedirect()方法的URL进行重写。
//向会话域中添加数据
session.setAttribute("key1","hahaha");
String url = resp.encodeRedirectURL("session.jsp");
// resp.sendRedirect(url);//重定向到jsp页面,因为是同一次会话,该页面也可以查看保存在session中的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Session测试</title>
</head>
<body>
<%= session.getAttribute("key1").toString()%>
<a href="<%= response.encodeURL("index.jsp")%>">超链接也可以使用URL重写</a>
</body>
</html>
进行url重写后,在浏览器中设置禁用Cookie,此时在url后就可以看到重写后的url(不禁用的情况下可能看不到)
补充:
Session和Cookie之间的区别
Cookie | Session |
---|---|
客户端浏览器的会话技术 | 服务器端的会话技术 |
将服务器传递的一些数据保存在浏览器上(Cookie) | 将同一用户和服务器的多次请求和响应产生的信息保存在Session(会话)域中 |
这些数据由浏览器来决定存不存储,不太安全(也可能被人为修改) | 保存在服务器中,相对安全一些(这里的安全是指会不会丢失) |
存储的数据必须是小量文本信息 | 存储的数据可以是任意数量大小、任意类型 |