一、会话技术

1、概述

会话是浏览器和服务器之间的多次请求和响应。

为了实现某一个功能,浏览器和服务器之间可能会产生多次的请求和响应,从浏览器访问服务器开始,到访问服务器结束,浏览器关闭为止,这期间产生的多次请求和响应加在一起就称之为浏览器和服务器之间的一次会话。

2、功能

在一次会话的范围内的多次请求间共享数据。

3、常用技术

在 Java 中有以下两种会话技术:

  • 客户端会话技术:Cookie

  • 服务端会话技术:Session

实际上,除了传统的 Cookie 和 Session 技术,近些年来开始流行无状态的会话技术,常用的是JWT技术,在我之前的一篇文章《JWT简介与基本原理》对该技术进行了详细介绍,有兴趣的可以阅读这篇文章。

下面我们将分别对 Cookie 和 Session 技术进行详细介绍。

二、Cookie

1、概念

Cookie 是一段不超过 4KB 的小型文本数据,由一个名称、一个值和其它几个用于控制 Cookie 有效期、安全性、使用范围的可选属性组成。这是一种客户端会话技术,用处是将数据保存到客户端。

2、实现原理

下面通过一张图来说明 Cookie 的实现原理:

Cookie的实现原理

通过上图,我们不难发现,Cookie 本质上是通过 HTTP 报文的请求头和响应头来实现的。当客户端第一次向服务器发送请求后,服务器在响应头中添加上Set-Cookie: cookie_name=cookie_value,客户端(浏览器)接收到请求数据后将 Cookie 存放在内存中(默认情况下)。之后当客户端再次向服务器发送请求时会在请求头上加上Cookie: cookie_name=cookie_value,服务器就可以根据请求头获取到 Cookie 并进行相应的操作。

3、基本用法

下面介绍如何使用 Cookie 实现客户端与服务器之间的会话。

(1)创建Cookie对象,绑定数据(访问某一Servlet时存储数据)

1
2
3
4
5
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("msg", "hello");
}

(2)发送Cookie对象(访问某一Servlet时存储数据)

1
2
3
4
5
6
7
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("msg", "hello");
// 2.发送Cookie
response.addCookie(cookie);
}

(3)获取Cookie,拿到数据(之后访问另一个Servlet时读取数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 3.获取Cookies
Cookie[] cookies = request.getCookies();
// 4.遍历Cookies
for (Cookie cookie : cookies) {
// 获取Cookie名称
String name = cookie.getName();
// 获取Cookie值
String value = cookie.getValue();
// 打印输出
System.out.println("name: " + name + "value: " + value);
}
}

注:Tomcat 8 之前的版本不能存储中文,之后的版本支持存储中文数据。如果使用的Tomcat的版本不支持中文则需要将中文数据进行转码,一般采用URL编码。

4、发送多个Cookie

可以创建多个Cookie对象,只需调用多次方法即可。

1
2
3
4
5
6
7
8
9
10
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie1 = new Cookie("msg", "hello");
Cookie cookie2 = new Cookie("name", "frank");
// 2.发送Cookie
response.addCookie(cookie1);
response.addCookie(cookie2);

}

此时响应头需要添加以下内容:

1
2
Set-Cookie: msg=hello
Set-Cookie: name=frank

之后客户端请求头需要添加以下内容:

1
Cookie: msg=hello;name=frankfang

5、Cookie的存活时间

默认情况下 Cookie 存放在浏览器内存中,因此当浏览器关闭后 Cookie 数据就会被销毁。不过可以设置 Cookie 的生命周期实现持久化存储,下面将介绍如何实现 Cookie 的持久化存储:

1
2
3
4
5
6
7
8
9
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("msg", "hello");
// 2.设置Cookie的存活时间
cookie.setMaxAge(300); // 将Cookie持久化到硬盘,在浏览器关闭后的300秒之内保存Cookie,300秒之后自动删除Cookie
// 3.发送Cookie
response.addCookie(cookie);
}

注意其中的setMaxAge(int seconds)方法,下面对该方法的参数进行介绍:

  • 正数:将Cookie数据写到硬盘的文件中,持久化存储
  • 负数:默认值
  • 零:删除Cookie信息

6、Cookie共享

假设在一个 Tomcat 服务器中部署了多个 Web 项目,默认情况下这些 Web 项目中的 Cookie 是不能共享的。如果需要共享,可以通过 Cookie 中的setPath(String path)方法来设置 Cookie 的获取范围,默认情况下设置为当前项目的虚拟目录,可以将其设置为根目录/,这样即可实现共享。

如果是不同 Tomcat 服务器之间需要共享数据,则可以通过setDomain(String path)方法设置项目的域名,不同 Tomcat 服务器上部署的项目如果顶级域名相同,则多个服务器之间的 Cookie 可以共享。

7、总结

Cookie 具有以下特点:

  • Cookie存储数据在客户端
  • 浏览器对于单个Cookie的大小有限制(4KB 左右),对同一个域名下的总Cookie数量也有限制(20 个)

Cookie 的作用:

  • Cookie 一般用于存储少量的不敏感的数据
  • 在不登录的情况下完成服务器对客户端的身份识别

三、Session

1、概念

Session 是一种服务器端会话技术,作用是在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。

2、实现原理

下面通过一张图来介绍 Session 的原理:

Session的实现原理

Session 实现上是依赖 Cookie 的。客户端首先向服务器发送请求,服务器在内存中创建一个 Session 对象并将这个 Session 的 ID 写入Cookie中,格式为JSESSIONID=xxxxx。之后客户端在发送请求时携带 Cookie,服务器获取 Cookie 并读出Session 的 ID,然后从内存中获取对应的 Session。

3、基本用法

在 Java 中通过HttpSession接口来使用 Session,下面通过一张表格来介绍 Session 接口的常用方法:

方法 & 返回值 解释
Object getAttribute(String name) 返回在此会话中用指定名称绑定的对象,如果名称下没有对象绑定,则返回null
void setAttribute(String name, Object value) 使用指定的名称将对象绑定到此会话。
void removeAttribute(String name) 从此会话中删除用指定名称绑定的对象。

下面来演示如何使用HttpSession接口来实现客户端与服务器之间的会话。

(1)首先需要获取HttpSession对象以存储数据(访问某一Servlet时存储数据)

1
2
3
4
5
6
7
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取Session
HttpSession session = request.getSession();
// 2.存储数据
session.setAttribute("msg", "hello");
}

(2)获取HttpSession对象以读取数据(之后访问另一个Servlet时读取数据)

1
2
3
4
5
6
7
8
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取Session
HttpSession session = request.getSession();
// 2.获取数据
Object msg = session.getAttribute("msg");
System.out.println(msg);
}

4、生命周期

(1)当客户端关闭后,服务器不关闭,两次获取的Session是否为同一个?

默认情况下不是,因为会话已经结束。如果需要获取的Session为同一个,可以采用以下方法实现:

1
2
3
4
5
6
7
8
9
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取Session
HttpSession session = request.getSession();
// 2.客户端关闭后,Session也能相同
Cookie cookie = new Cookie("JSESSIONID", session.getId());
cookie.setMaxAge(60 * 60);
response.addCookie(cookie);
}

(2)客户端不关闭,服务器关闭后,两次获取的Session是同一个吗?

在回答该问题之前,需要介绍两个概念:

  • Session 的钝化:在服务器正常关闭之前将 Session 对象序列化到硬盘上

  • Session 的活化:在服务器启动后将 Session 文件转化为内存中的 Session 对象

Tomcat 服务器支持 Session 的钝化和活化(前提是正常关闭 Tomcat 服务器),但在 IDEA 中使用 Tomcat 服务器则不支持。

(3)Session什么时候被销毁?

  • 服务器关闭进行销毁

  • Session对象调用invalidate()方法时进行自我销毁

Session 默认失效时间为 30 分钟,我们可以在 Tomcat 的配置文件conf/web.xml中修改默认的失效时间:

1
2
3
<session-config>
<session-timeout>30</session-timeout>
</session-config>

5、总结

Session的作用:

  • 用于存储一次会话的多次请求的数据,存在服务器端
  • 可以存储任意类型,任意大小的数据

Session与Cookie的区别:

  • Session存储数据在服务器端,Cookie在客户端
  • Session没有数据大小限制,Cookie有
  • Session数据安全,Cookie相对不安全