Java-Web基础之Session
变量命名应该要名副其实,如果名称需要注释来补充,那就不算名副其实。——《Clean Code》
Http协议的”无状态性”
Http协议是无状态的。这意味着服务器在处理完一个请求后,不会保留任何关于这个请求的上下文信息。它不记得之前发生了什么,也不关系将来会发生什么。
举例:
- 你第一次访问一个网站,服务器会响应你的首页
- 你第二次访问同一个网站的另一个页面,服务器会像第一次一样处理,它并不知道你刚刚访问过首页,也不知道你是同一个用户。
- 每次请求都是独立的,服务器不会记住你是谁,或者你之前做过什么
但是在实际的Web应用中,我们几乎总是需要识别用户,并维持他们的某种状态。
Session 的概念与作用
为了解决HTTP的无状态性问题,并实现在多次请求之间保持用户的状态,我们引入了Session(会话机制)。
什么是Session?
简单来说,Session是Web服务器为每个独立的用户(或浏览器会话)在服务器端分配并维护的一块独立的存储空间。这块存储空间用于保存特定用户在整个会话期间的关键数据。
- 服务器端存储:Session数据是存储在服务器内存中的,而不是客户端
- 唯一标识:每个Session都有一个唯一的标识符,通常称为Session ID
- 会话范围:Session 的生命收起通常从用户第一次访问Web应用开始,到用户关闭浏览器(或达到超时时间)结束
Session如何工作
这里简单描述一下Session如何利用HTTP来实现状态保持:
- 用户首次请求:当用户第一次访问Web应用时,Web服务器会检测到这是一个新的会话。
- 创建Session:服务器会为这个用户创建一个新的Session对象,并生成一个唯一的Session ID
- 发生Session ID给客户端:服务器会将这个Session ID作为响应的一部分发送给客户端。最常见的方式是将其写入一个特殊的Cookie,然后发送给浏览器。
- 客户端存储Session ID:浏览器收到服务器发送的Cookie后,会将其存储起来。
- 后续请求携带Session ID:用户在同一个会话中访问该网站的其他页面时,浏览器会自动将指责给存储的Session ID Cookie 附加到后续的每一个Http请求中,发送给服务器。
- 服务器识别Session:服务器接收到请求后,会从请求中解析出Session ID。然后,它会根据这个Session ID到自己的内存中查找对应的Session对象。如果找到了,就说明服务器认出了这个用户,可以获取到之前存储在Session中的所有数据,从而实现状态的保持。
HttpSession 接口
HttpSession
接口时Java Servlet API 的核心组成部分,它提供了在服务器端管理和访问Session数据的方法。当你需要存储、检索或移除特定用户的数据时,都会用到它。
获取HttpSession对象
HttpServletRequest.getSession()
方法
用法:
1 |
|
工作原理:
- 当调用
request.getSession()
时,Servlet容器会首先检查当前请求中是否包含了有效的Session ID - 如果Session ID有效,并且服务器上存在对应的
Session
对象,那么容器就会返回这个已经存在的HttpSession
对象 - 如果没有Session ID 或Session ID已经过期,那么容器会创建一个新的
HttpSession
对象,生成一个新的Session ID,并将这个Session ID封装在一个Cookie中,随着响应发给客户端
HttpServletRequest.getSession(boolean create)
方法
这个方法允许你控制是否在Session不存在时创建新的Session。
1 |
|
create = true
:行为与getSession()
相同create = false
:当请求中没有关联的Session或者Session失效,此方法会返回null,而不会创建新的Session。
存储和获取属性(数据的读写)
HttpSession
对象就像一个 MAP
容器,允许你存储任意的Java对象。
setAttribute(String name,Object value)
方法
存储数据到Session。将一个对象绑定到Session中,通过一个字符串名称来标识。
name
:属性的名称(键),类型为Stringvalue
:属性的值,类型为Object
。你可以存储任何可序列化的Java对象
1 |
|
getAttribute(String name)
方法
通过属性名称获取存储在Session中的对象。
1 |
|
注意,
getAttribute()
方法返回的时Object
类型,所以你需要精细强制类型转换到你存储的原始类型。
removeAttribute(String name)
方法
从Session中删除指定的属性。
1 |
|
当你不再需要Session中的某个数据时,即使移除可以节省服务器内存。
Session ID
getId()
方法
每个 HttpSession
对象都有一个由服务器生成的唯一字符串ID。这个ID是服务器用来识别不同客户端的关键。
1 |
|
Session生命周期管理
setMaxInactiveInterval(int interval)
方法
设置Session最大不活动时间。这个方法设置Session在不活跃(即没有客户端请求与该Session关联)多少秒后失效。
1 |
|
- interval参数以秒为单位。如果设置为0或负数,表示Session将永不失效。
- 默认超时时间:Web应用服务器通常由默认的Session超时时间(如30分钟),也可以在web.xml中进行全局配置。
invalidata()
方法
使Session立即失效。这个方法会立即终止当前的Session,并从服务器内容中移除所有与之关联的数据。
1 |
|
- Session销毁后,Session中的所有属性都将被移除,且该Session ID不再有效。后续客户端再带着该Session ID发送请求,服务器会认为这是一个新的会话,并可能创建一个新的Session。
Cookie
Cookie是一种由服务器发送到用户浏览器并存储在浏览器本地的小数据块。当浏览器再次向同一服务发送请求时,它会自动将这个Cookie连同请求一起发送回服务器。
一个由tomcat设置的Cookie如下:
1 |
|
- 客户端存储:Cookie数据是存储在客户端浏览器上的。
- 大小限制:通常每个Cookie有大小限制(如4KB),且每个域名下的Cookie数量也有限制。
- 生命周期:Cookie可以设置为会话级别的
Session ID通过Cookie传递的详细过程
用户首次访问:
当用户访问一个Web应用时,浏览器发送一个不带任何Session ID的HTTP请求给服务器。
当在请求处理流程中执行
HttpServletRequest.getSession()
语句后,就会在服务器内存中为这个新用户创建一个新的HttpSession
对象。服务器为这个新的Session生成一个唯一的Session ID。
在服务器返回给浏览器的HTTP响应中,服务器会添加一个
Set-Cookie
响应头。这个Set-Cookie
头会包含生成的Session ID,通常以JSESSIONID
(这是Java Servlet 规范默认的SessionID Cookie名称)作为键名。1
2
3
4
5// 服务器响应头示例
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Set-Cookie: JSESSIONID=ABCDEF1234567890; Path=/myWebApp; HttpOnly
...
浏览器存储Cookie:
- 浏览器接收到服务器的响应后,会解析Set-Cookie头,并将Cookie中的内容储存在本地。
用户后续请求:
当用户在同一个浏览器会话中,再次向同一个Web应用发送请求时,浏览器会自动查找并把之前存储的
JSESSIONID
Cookie添加到HTTP请求头中,发送给服务器。1
2
3
4
5
6// 浏览器请求头示例
GET /myWebApp/products HTTP/1.1
Host: example.com
Cookie: JSESSIONID=ABCDEF1234567890
User-Agent: ...
...
服务器识别Session:
- 服务器接收到请求后,会从请求中读取
Cookie
字段,并解析出JSESSIONID
的值。 - 服务器使用这个SessionID去查找其内存中是否有对应的HttpSession对象。
- 服务器接收到请求后,会从请求中读取