Session & Cookie
两者的职责和作用
讲到 Session 和 Cookie 就不得不提他们属于什么技术。
会话技术
从用户打开浏览器开始发送请求到服务器,一次会话正式建立,中间可包含多次请求和返回,直到一方断开连接,会话结束。
实际上就是一种跟踪机制,为什么会需要这种技术呢?
学习过网络通讯或者 Java Web 的小伙伴应该知道,HTTP 是属于一种无状态的,一次请求响应后,同一用户再次请求,服务器就不知道原来用户的状态,也就是无法保存和跟踪用户状态。典型的例子就是:用户在添加商品时,进行结算,Web 服务器就不知道是什么用户买了些什么东西。此时需要使用会话技术进行保存和跟踪用户状态。
会话技术分为两种:
- Cookie:客户端会话技术
- Session:服务端会话技术
Cookie
Cookie 实际上是一小段文本(key-value),根据 Cookie 类型不同,存储方式也有不同,但是相同的是,都是客户端保存 Cookie,在请求时,如果服务器需要记录用户状态,就使用 response 发送一个唯一标识的 cookie,浏览器就会将这个 cookie 保存起来,下一次该用户进行请求时会携带自己有效的 cookie 给服务器进行辨识,服务器就会根据业务逻辑读取 cookie 中的信息(包括是否合法,操作数据等)来辨认用户状态。
由于会话技术时 HTTP 协议扩展技术,所以需要浏览器的支持,现在大部分主流浏览器都支持 cookie 技术。
Cookie 分类
- 会话级 Cookie:存储在内存中,如果浏览器关闭,则 Cookie 失效,即 cookie 无时效。
- 持久型 Cookie:设置了 cookie 的时效,存在磁盘中,超过时效则自动删除失效。
简易原理图
request 和 response 可以同时使用多个 cookie,在 Java 中使用的时 Cookie 类实例来反映 cookie。
Cookie 常见性质
不可跨域名性质:
搜狗的 cookie 和百度的 cookie,两者是不能互相操作 cookie 的,因为 cookie 是由浏览器来管理,浏览器可以保证此特性。主要原因是因为两者的域名不一样。
路径和域名:
Cookie 的常见属性有 maxAge、name、path、domain,其中 path 就是路径,domain 就是域名。
-
maxAge:cookie 的有效期时间,0 为立即删除,单位是秒,为正数将其持久化在磁盘中,-1 为临时的,会话级别,关闭浏览器即刻失效。
-
name:cookie 的标识名。
-
domain:指定了哪些主机地址可以接收 Cookie,例如:``images.xxx.com
和www.xxx.com,两者的 cookie,如果设置了 cookie 的domain 参数为 .xxx.com`,这样两个二级域名都可以共享 cookie 了。注意:上诉中一级域名为
xxx.com,二级域名则是images.xxx.com和www.xxx.com。 -
path:路径使用 cookie 的路径,设置为
/则代表所有路径都可以使用该 cookie。例如:
path='/web',那么/web/app、/web/app/add子路径都可以使用。如果
path='/web/'则作用域只能在
在 Java 中 Cookie 类的方法需要自行查看文档。
详细讲一下不同域名共享 Cookie 以及 Cookie 的作用域
准备工作:
两个临时域名:image.newlyl.com & www.newlyl.com
两个url(Servlet):/Demo1/Web & /Demo1
Demo1:(进行一些 Cookie 的初始化)
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
Cookie[] cookies = req.getCookies();
System.out.println("=====/Demo1======");
if (cookies!=null&&cookies.length>0) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
System.out.println(cookie.getPath());
System.out.println(cookie.getDomain());
System.out.println(cookie.getComment());
}
}
Cookie cookie1 = new Cookie("count1","cookieValue-1");
Cookie cookie2 = new Cookie("count2","cookieValue-2");
Cookie cookie3 = new Cookie("count3","cookieValue-3");
Cookie cookie4 = new Cookie("count4","cookieValue-4");
cookie1.setPath("/Demo1/");
cookie1.setDomain(".newlyl.com");
cookie1.setMaxAge(60*60);
cookie2.setPath("/");
cookie2.setDomain(".newlyl.com");
cookie2.setMaxAge(60*60);
cookie3.setPath("/Demo1/Web");
cookie3.setDomain(".newlyl.com");
cookie3.setMaxAge(60*60);
cookie4.setPath("/Demo1/");
cookie4.setDomain(".newlyl.com");
cookie4.setMaxAge(60*60);
resp.addCookie(cookie1);
resp.addCookie(cookie2);
resp.addCookie(cookie3);
resp.addCookie(cookie4);
resp.setContentType("text/html;charset=UTF-8");
req.getRequestDispatcher("show01.jsp").forward(req,resp);
}
准备了 4 个 Cookie,分别在 path 和 domain 上有不同。
Demo1Web:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
Cookie[] cookies = req.getCookies();
System.out.println("=====/Demo1/Web======");
if (cookies!=null&&cookies.length>0) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
System.out.println(cookie.getPath());
System.out.println(cookie.getDomain());
System.out.println(cookie.getComment());
}
}
req.getRequestDispatcher("Web/show01.jsp").forward(req,resp);
}
启动程序,首先测试同一地址下的 Cookie 作用域:
第一次调用 Demo1 请求初始化 cookie 实例,第二次调用查看 path=/Demo 下的所有可访问的 cookie
只有 count2 和 count4 可以访问,count1 和 count3 不能访问。
再调用 Demo1Web 请求:

count 1、2、3、4 都能访问到,则代表 path 的含义,
此时诺调用其他url,查看 cookie,只能查看到 count2,因为其他 cookie 都是需要在 Path 为 /Demo1 或 /Demo1/Web 才能查看,作用域不同。
再测试不同域名共享 cookie:
两个域名调用 Demo1Web 请求:

控制台打印结果是 count1、2、3、4 都能访问 Demo1 请求初始化的 4 个 cookie。
即 Cookie 的作用域由 Path 和 Domain 一起决定。
Session
与 Cookie 不同的是,它是保存在服务器端,是服务器跟踪用于状态的一种会话机制,会给以 Cookie 的形式发送唯一的 SessionID 给客户端进行保存。
在 Java 中是使用 HttpSession 类来操作 Session 对象。
-
获取 Session :
request.getSession([Boolean create]),可以无参,也可以有参。request.getSession() 等价 request.getSession(true)如果没有 Session 则新建一个 Session 返回。request.getSession(false)如果 Session 没有则返回 null。 -
操作 Session 数据:共享一次会话期间相关的数据
- `session.setAttribute()`:设置 Session 域的数据。
- `session.getAttribute()`:获取 Session 域的数据。
- `session.removeAttribute()`:移除 Session 域的数据。
大致原理
在上诉中可以知道 Session 也是需要依靠 Cookie 来实现的,Session 的功能较 Cookie 强大,而服务器中只保存 Session 对象,所以需要客户端发送请求时持有 SessionID 的 Cookie 来找到对应的 Session,从而读取到 Session 的数据。
因为 Session 中可以存储数据,为防止存储数据量过大,需要进行销毁或移除数据,如果超时会自动销毁,也可以调用 session.invalidate() 进行手动销毁。
上图中可以看出,Cookie 中保存了 SessionID,主要作用是来找到服务器对应的 Session,那么为什么又要在服务器中弄一个 Session呢?如果浏览器禁止了 Cookie 那么 Session 又该怎么用?下面进行讨论。
讨论
有了 Cookie 为什么需要 Session?
这个就要谈起 Cookie 的本质了,Cookie 本质上是存储在客户端的,那么对其用户可见并可对其进行更改,且可存储和可使用的内容和次数有限,那么 Session,就比较好的完善了这些问题,由于 Session 的信息是保存在服务器中的,由唯一的 SessionID 确定对象实例,所以信息安全这一点可以较好的保障。
Session 由自己的域(作用域),可以在用户会话期间共享数据,同时比较 Cookie 要简单点。Cookie 存放数据一般只有 4 KB,数据量有限,只用 Cookie 记录用户所有状态,显然在数据量大的时候并不太实用,且不太安全。
使用 Session,数据存在服务器,只要 Cookie 持有 SessionID,即可。
且在编程过程中,不需要刻意将 SessionID 存入 Cookie 再将 Cookie 返回,响应体会带有 JSESSIONID 的参数(Google 浏览器为例)。
禁止了 Cookie 又该如何使用 Session?
Session 是依赖于 Cookie 的,如果浏览器禁了 Cookie,那么可以通过其他方式进行 SessionID 参数的传递。
因为 Cookie 中保存了 SessionID,且同一用户的 Cookie 只能自己持有(不考虑 Cookie 泄露),由于 Cookie 的特性不需要手动频繁的设置 SessionID 参数进行传递,但是本质上就是服务器拿到的 SessionID 进行判别即可,所以确定了痛点即可。
- URL 追加 SessionID 参数:可以前台加密传递,服务器接收后进行解析判别。
- 请求时携带 SessionID 参数:第一次请求时返回 SessionID,保存起来,有效期间请求时携带 SessionID 传递。
本质上是参数的传递。
总结两者使用场景
两者都比较重要且基础,所以根据特点小结一下两者的使用场景。
Cookie 体积小,用户可见,数量有限,本地保存,适用于数据量小,只用于进行特定的标记信息不涉及个人隐私信息。
- 标记用户是否已登录。
- 登录信息(用户名,登录时间,下线时间),不涉及密码,卡号家庭住址等隐私信息。
- 用户的一些商品喜好,关键字……
缺点就是:不可靠,不安全
Session 可以存储大量数据(所有数据堆积在 Session 也是不明智的选择),信息存储在服务器中,根据 SessionID 找具体 Session 对象。
- 登录状态(具体的一些信息,个人隐私信息理应保存在数据库中进行加密处理)
- 在会话期间进行数据共享。
对比 Cookie 安全可靠,简单方便。
但是不论时使用哪一种,我们都要对重要的信息进行加密处理。
还有一些具体的细节就不描述,因为没有使用到那去,什么钝化,活化啥的就没去探究了。先弄清楚基本使用的场景和本质,在碰到问题再去深究其中道道,可能比初学时一头扎入研究效率更好。
有话要说
在遇到问题时进行解决并总结,在总结中发现已存在或可能存在的问题进行处理。