Session & Cookie 会话跟踪技术
Cookie&Session出现的原因:HTTP协议的问题所在----HTTP无状态
HTTP协议是无状态的,也就是没有记忆力,-----一个会话中的多个请求之间无法直接共享数据
通过作用域去共享的数据是作用域中的数据,不是请求之间的数据
解决方法
-
传递参数的方式
-
直接在路径上带参数(麻烦且数据不安全, 不推荐)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>邮件列表</title> </head> <body> 欢迎:${username} <br/> <c:forEach items="${list}" var="email"> <a href="/http/content">${email}</a> <br/> </c:forEach> </body> </html>
package cn.wolfcode.web._01_http; @WebServlet("/http/content") public class ContentServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { // 处理请求编码 req.setCharacterEncoding("UTF-8"); // 接受请求参数 String username = req.getParameter("username"); req.setAttribute("username", username); // 模拟从数据库中查询到邮件内容,放到 request 作用域中 req.setAttribute("content", "这是邮件内容"); req.getRequestDispatcher("/WEB-INF/views/content.jsp").forward(req,resp); } }
问题:一次会话中多次请求,不共享数据,导致用户显示不出来。但若通过路径携带的方式解决该问题,会把用户信息暴露在路径上,不安全
-
-
会话跟踪技术
cookie和session
Cookie
概述: cookie是客户端技术
程序把每个用户的数据以 cookie 的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的 Web 资源时,就会带着各自的数据到服务器。这样,Web 资源处理的就是用户各自的数据了
思考:
问题 | 答案 |
---|---|
Cookie 是服务器端创建的还是客户创建的? | 服务器端程序创建 |
Cookie 从哪里带到哪里? | 服务器端 -> 客户端 |
Cookie 最终存在什么地方 | 浏览器 |
Cookie 什么时候实现数据共享 | 再一次访问服务器端资源时 |
Cookie 中数据的传递方向? | 浏览器 -> 服务器(Cookie)-> 浏览器(存入)-> 服务器(获取Cookie数据) |
Cookie原理?
当用户第一次发送数据到服务器时由服务器创建Cookie对象(封装用户数据),把Cookie响应给浏览器,当二次访问时用户不需要重新填写用户数据,由浏览器发送对应Cookie给服务器,服务器获取Cookie中的数据
Cookie 基本使用
-
创建Cookie对象
Cookie cookie = new Cookie (String name, String value);
属性 方法 描述 name getName() 共享数据(唯一) value getValue() 获取要共享的数据 -
响应Cookie对象给浏览器
使用响应对象中的addCookie(Cookie对象) 将数据响应给浏览器
response.addCookie(cookie);
-
服务端获取浏览器发送的Cookie
浏览器发送请求时,自动将Cookie发送到服务器,服务器程序直接获取即可
数据在请求中可以使用请求对象中的getCookies()方法获取所有的Cookie对象
Cookie[] cookies = request对象.getCookies();
-
响应对应数据给浏览器
- Java代码:
//创建Cookie对象,存入数据响应给浏览器 @WebServlet("/cookie/login") public class LoginServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //接收请求参数 String username = req.getParameter("username"); String password = req.getParameter("password"); if ("admin".equals(username) && "123456".equals(password)) { //将账号共享给index.jsp页面 req.setAttribute("username",username); //创建cookie对象同时设置了共享数据 //Cookie的默认路径是它所在Servlet的相对路径 Cookie cookie = new Cookie("username", username); //修改cookie的路径 cookie.setPath("/"); //将cookie中的数据响应到浏览器中 resp.addCookie(cookie); //账号密码正确,跳转到邮箱首页 req.getRequestDispatcher("/WEB-INF/views/cookie/index.jsp").forward(req,resp); } } }
//在Servlet中获取Cookie数据 @WebServlet("/cookie/list") public class ListServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //从cookie中接收共享数据 Cookie[] cookies = req.getCookies(); for (Cookie cookie : cookies) { if ("username".equals(cookie.getName())) { //System.out.println(cookie.getValue()); //req.setAttribute("username",cookie.getValue()); //break; //修改cookie //cookie.setValue("hhhh"); //将修改后的cookie重新响应给浏览器 //设置当前cookie存活的时间---默认是一个会话cookie cookie.setMaxAge(60*60*30*24); //resp.addCookie(cookie); } } req.getRequestDispatcher("/WEB-INF/views/cookie/list.jsp").forward(req,resp); } }
@WebServlet("/cookie/content") public class ContentServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //从cookie中接收共享数据 Cookie[] cookies = req.getCookies(); for (Cookie cookie : cookies) { if ("username".equals(cookie.getName())) { req.setAttribute("username",cookie.getValue()); break; } } req.getRequestDispatcher("/WEB-INF/views/cookie/content.jsp").forward(req,resp); } }
-
在JSP中获取Cookie数据----使用EL表达式
<%-- JSP获取cookie中的数据: ${cookie.cookie的名字.value} cookie: EL的内置对象,以Map结构封装了当前这一次请求所有的Cookie key是cookie的name value是cookie对象 cookie.cookie名字: 对应的cookie对象 cookie.cookie的名字.value: cookie的对象的属性名 --%> <div align="left">欢迎[${cookie.username.value}]登录</div> <br> <a href="/cookie/content">邮件一</a> <br> <a href="/cookie/content">邮件二</a> <br> <a href="/cookie/content">邮件三</a> <br> <a href="/cookie/content">邮件四</a> </body> </html>
修改Cookie数据
- 调用 Cookie 对象的 setValue 方法来覆盖原本的数据。
- 重新创建一个同 name 的 Cookie 对象
注意:需要将修改之后的 Cookie 发送到浏览器中进行更新
resp.addCookie(修改后或者新的 Cookie 对象);
@WebServlet("/cookie/list")
public class ListServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 调用业务方法来处理请求,从数据库中查询邮件列表(模拟)
List<String> list = Arrays.asList("邮件1", "邮件2", "邮件3");
req.setAttribute("list", list);
String username = null;
Cookie[] cookies = req.getCookies();
for(Cookie cookie : cookies) {
if("username".equals(cookie.getName())) {
// 方式一:修改 Cookie 中的数据
cookie.setValue("wolfcode1");
// 方式二:创建新的 Cookie 对象,设置名称为 username
// cookie = new Cookie("username", "wolfcode2");
// 记得使用 Response 对象响应回浏览器
resp.addCookie(cookie);
break;
}
}
req.getRequestDispatcher("/WEB-INF/views/list.jsp").forward(req, resp);
}
}
设置Cookie存活时间
Cookie 对象的 setMaxAge(int expiry);
expiry数值 | 例子 | 含义 |
---|---|---|
大于0 | Cookie 存活的时间,单位为秒,例:60 秒 | |
小于0 | 立即删除当前 Cookie 对象 | |
等于0 | setMaxAge(-1) | 会话 Cookie,浏览器关闭则销毁 |
Cookie的分类
按客户端存储位置
-
内存Cookie
内存 Cookie 由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘Cookie 保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘 Cookie 不会被删除,其存在时间是长期的。所以,按存在时间,可分为
- 非持久 Cookie
- 持久 Cookie
-
硬盘Cookie
默认情况下Cookie属于会话Cookie,即浏览器关闭则失效,无法使用
删除Cookie
删除 Cookie 只需要使用设置 Cookie 存活时间的方法即可,需要注意的是一般是中途删除
Cookie,不是创建了后马上删除,所以在设置删除之后需要重新发送给浏览器去更新删除
即
Cookie对象.setMaxAge(0);
resp.addCookie(Cookie 对象);
Cookie的域和路径作用
就是让浏览器能正确的区分每个Cookie是哪个请求需要的(先找域下所有的Cookie后找路径对应的Cookie发送给服务器)----安全
为了让浏览器可以识别 Cookie 发送给对应的服务器,以及识别哪些请求需要携带 Cookie,默认
Cookie 都带了服务器的识别标识以及需要带 Cookie 的资源标识,这是出于安全考虑,为了保护
Cookie 中的数据不被带到其他服务器中去
域: 识别服务器,包括IP:端口或者域名:端口,可通过 Cookie 对象的 setDomain 方法设置;默认
Cookie 中的域是创建 Cookie 的服务器的域名,
分类:
- 一级(主)域名:baidu.com
- 多级域名:news.baidu.com
若想要在相同的主域名下来共享 Cookies 数据,例如,百度和百度地图,百度音乐共用账号,则只需要设置 Cookie 的 domain 即可。若主域不同,是无法共享 Cookie 数据
路径: 用于识别资源,通过Cookie对象的setPath方法设置------默认是创建Cookie的资源的路径
若想要在访问服务器上的任意资源都带上Cookie,则只需要在创建Cookie之后设置下path为/即可
cookie.setPath(“/”);
Cookie应用场景
- 存用户标识,解决 HTTP 无状态问题
- 登录时记住用户名
- 未登录情况实现购物车
Cookie的问题
- 若是一个用户一台电脑,没有问题,但是若多个人公用一个电脑就存在安全性问题
- 一个 Cookie 只能设置一个值,值须字符串类型
- 一台服务器在一个客户端存储的 Cookie 大小和数量有限
- Cookie 大小限制在 4KB 之内
- 一台服务器在一个客户端最多保存 20 个 Cookie
- 一个浏览器最多可以保存 300 个 Cookie
Session
概述:Session是服务端技术
服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于 session 为用户浏览器独享,所以用户在访问服务器的 Web 资源时,可以把各自的数据放在各自的 session 中,当用户再去访问服务器中的其它 Web 资源时,其它 Web 资源再从用户各自的 session 中取出数据为用户服务
思考
问题 | 答案 |
---|---|
Session 谁来创建 | 服务器 |
Session存在什么地方 | 服务器 |
Session什么时候实现数据共享 | 再次访问服务器资源时 |
Session中数据的传输方向 | 浏览器->服务器(Session)-------数据在服务器 |
服务器如何识别不同用户的Session | 浏览器->服务器(Session) sessionId 浏览器sessionId->服务器 |
Session的原理
Session 其底层依然需要依赖 Cookie 来传递 Session 的 id 值。存 sessionId 的 Cookie 为会话
Cookie
所以 Session 在浏览器关闭之后就无法使用了。原因是 sessionId 丢失了,服务器会在 30 分钟内清除无操作的 Session 对象
Session的基本使用
-
获取Session对象
方法 作用 getSession(true)判断是否存在 Session,存在则获取,不存在则创建新 Session 对象返回 getSession(false)判断是否存在 Session,存在则获取,不存在则返回 null (不符合需求) getSession() 判断是否存在 Session(浏览器是否带了 sessionId),存在则获取,不存在则创建新 Session 对象返回(推荐) -
Session数据共享
方法 作用 setAttribute(String name, Object value); 设置属性名和属性值 getAttribute(String name) 通过属性名去获取属性值 removeAttribute(String name) 从 Session 中移除指定属性名的属性值(删除部分数据使用) invalidate() 移除整个 Session 对象,删除所有的属性和属性值(删除全部数据使用) -
Session的超时管理------无操作的时间
设置会话的有效时间
-
全局修改
在web.xml中配置
-
局部修改
// 设置 session 超时时间(单位秒) session.setMaxInactiveInterval(int interval);
-
-
Session的使用规范
Session的属性命名格式一般为: XXX_IN_SESSION(唯一的)
session.setAttribute("USER_IN_SESSION", 值);
Session可以存放多个数据,如果数据之间有联系的话可以将这部分数据封装成对象之后再存入Session中
服务器在做 Session 数据共享时,Session 中的存储的对象类型须实现 java.io.Serializable 接口
-
URL重写
-
为什么要重写URL
Session是基于Cookie的,sessionId是存储在浏览器上的,用户可以选择不接受Cookie或者禁用Cookie,此时Session是无效的
-
解决方案: 在请求路径后面拼接jsessionid,使用 ; 间隔
-
在Servlet中重写URL
在请求的URL后拼接jsessionid--------response.encodeURL(“/session/list”)
此时会自动检测用户是否接收Cookie,接收Cookie则不拼接,不接受Cookie则拼接 jsessionid
-
在JSP中重写URL
脚本重写(不使用)
EL重写----效果同上
- ${pageContext.response.encodeURL(“/session/list”)}
-
-