目录
4. 浏览器关闭, 服务器端对应的Session对象会销毁吗
8. HttpSession和HttpServletRequest接口的对比
1. javaweb中的Session
1. Session表示会话, 不止在javaweb中存在, 只要是web开发, 都会有这种会话机制
2. 在java中会话对应的类型为: java.servlet.http.HttpSession, 简称session/会话
3. Cookie可以将会话状态保存在客户端, 而HttpSession可以将会话状态保存在服务器端
4. HttpSession对象是一个会话级别的对象, 一次会话对应一个HttpSession对象
5. 什么是一次会话?
目前可以这样理解, 用户打开浏览器, 访问web服务器, 在浏览器上发送多次请求
直到最后关闭浏览器(停止访问web服务器), 表示一次完整的会话.
所以一次会话包括多次请求.
例子如下:
public class HttpSessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取ip
String ip = request.getRemoteAddr();
// 获取会话状态
HttpSession session = request.getSession();
// 不同的用户访问会有不同的Session
// 如果用户不变, 连续访问, Session也不变
System.out.println(ip + "的Session为" + session);
}
}
直接访问多次:始终打印: 0:0:0:0:0:0:0:1的Session为org.apache.catalina.session.StandardSessionFacade@71d180de
关闭浏览器后再次访问: 0:0:0:0:0:0:0:1的Session为org.apache.catalina.session.StandardSessionFacade@1fff9fca
两次并不一样, 这是因为两次不是一个会话
6. web服务器一直为当前用户维护着一个会话对象, 就是HttpSession对象
7. 在web容器中, 一直维护了大量的HttpSession对象, 换句话说, Web容器中应该存在一个session列表(Map结构)
思考: 为什么当前会话中的每一次请求可以获取到属于自己的会话对象?
举个生活中的例子: 上体育课, 我打篮球, 这个篮球手感不错, 我想下一节课继续用这个篮球, 我给这个篮球上
做一个标记, 然后再脑子中记住这个标记, 下节课我来的时候就找这个标记标的篮球
这里篮球就是一个Session对象, 篮球上的标记是这个Session对象对应的Cookie, 在服务器中,
脑中的记忆就像是客户端的Cookie, 如果我脑中忘记这个标记就代表我找不到这个篮球了
这对应浏览器清理缓存时候将Cookie清除, 所以关闭浏览器访问的Session是不同的
2. Session实现的底层原理:
原理如下:
打开浏览器, 在浏览器上发送首次请求
服务器会创建一个HttpSession对象, 该对象代表一次会话
同时生成HttpSession对象对应的Cookie对象, 并且Cookie对象的name是JSESSIONID, Cookie的value是32位长度的字符串
服务器将Cookie的value和Session对象绑定到Session列表中
服务器将Cookie完整的发送给浏览器客户端
浏览器将Cookie保存到缓存中, 只要浏览器不关闭, 或者不删除Cookie信息, Cookie不会消失
当再次发送请求时, 会自动提交缓存中的Cookie
服务器接收到Cookie, 验证该Cookie的name确实是JSESSIONID, 然后获取Cookie中的value
通过Cookie的value在Session列表中找对应的对象
抓个包看看情况:
第一次访问资源的时候, 在响应对象中生成了如下的Cookie信息
第一次响应对象生成的Cookie: JSESSIONID=22494267CE4228BD051AF151C5C71200;
此时标准输出打印如下(代码还是上面的代码): 0:0:0:0:0:0:0:1的Session为org.apache.catalina.session.StandardSessionFacade@677aed17
不关闭浏览器刷新, 在新的包中请求对象中发送了如下Cookie信息
不关浏览器刷新发送的Cookie: JSESSIONID=22494267CE4228BD051AF151C5C71200
这两条Cookie一模一样
此时标准输出打印如下(代码还是上面的代码): 0:0:0:0:0:0:0:1的Session为org.apache.catalina.session.StandardSessionFacade@677aed17
现在关闭浏览器(代表清理缓存), 或者清除当前页面的Cookie
在响应对象中又生成了新的Cookie
响应对象生成的新Cookie信息如下Cookie: JSESSIONID=AB5FED2711F6427A92709C4EB8ED3A62;
和之前的Cookie信息不一样,
此时标准输出打印如下(代码还是上面的代码): 0:0:0:0:0:0:0:1的Session为org.apache.catalina.session.StandardSessionFacade@3598841e
说明Session对象也不一样了
3. 浏览器禁用Cookie会出现的问题
浏览器禁用Cookie则浏览器的缓存中不在保存Cookie
导致在同一次会话中, 无法获取到对应的会话对象
禁用Cookie之后, 每一次获取的会话对象都是新的
浏览器禁用Cookie之后, 如果还想拿到对应的Session对象, 必须使用URL重写机制
将上一次的Cookie记录下来, 在URL栏的后面加上";jsessionid=xxxxxx"(xxxxx是上一次的JSESSIONID复制过来的)
4. 浏览器关闭, 服务器端对应的Session对象会销毁吗
不会销毁, 因为B/S架构的系统Http协议, 而http协议是一种无连接无状态的协议, 服务器根本不知道你浏览器关闭了(会话结束了).
什么是无连接/无状态?
典型的例子是, 断网之后加载好的网页依旧可以显示, 服务器不知道浏览器端已经断开连接了
请求的瞬间浏览器和服务器之间的通道是打开的, 请求响应结束之后, 通道关闭
这样做的目的是降低服务器的压力
5. Session对象在什么时候销毁
web系统中引入了Session超时的概念, 当很长一段时间(这个时间可以给定)
没有用户访问该session对象, 此时session对象超时, web服务器会自动回收Session对象
可以在web.xml文件中配置
加入下面语句
<session-config>
<session-timeout>120</session-timeout>
</session-config>
这个代表120分钟内, 没有用户访问这个Session对象, 会被web服务器回收
不配置时候, 默认是30分钟
经常出现这种现象, 在某个页面上很久为操作, 再次操作时会显示让你重新登录
6. 到底什么是一次会话?
本质上, 会话是指一个终端用户与交互系统进行持续通讯的一次过程, http协议是一种无连接无状态的协议, 其中通过Session和Cookie机制确保一次会话的状态
http中Session对象被创建到Session对象被销毁叫为一次会话的全过程
但是大部分情况下, 用户打开浏览器, 在浏览器上进行操作, 然后将浏览器关闭, 通常代表一次会话结束.
7. HttpSession相关的常用方法
创建或者获取Session, 通过request对象创建
request.getSession()/request.getSession(true) // 这两个方法一样, 获取Session对象, 如果没有Session对象则新建对象
request.getSession(false) // 获取Session对象, 如果没有Session对象则返回null
HttpSession是一个接口
void setAttribute(String name, Object value) // 存某一条信息
Object getAttribute(String name) // 取某一条信息
关于这两个放, 给出例子:
这个Servlet是向会话对象中存入数据
public class SetSessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从请求对象中获取Session
HttpSession session = request.getSession();
// 向Session存入数据
session.setAttribute("username", "zhangsan");
}
}
下面这个Servlet是从会话对象中取出数据
public class GetSessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 从请求对象中获取Session
HttpSession session = request.getSession();
// 从Session中获取数据
Object username = session.getAttribute("username");
// 打印数据
System.out.println(username);
}
}
先访问"/setSession", 再访问"/getSession"打印结果如下
zhangsan
这说明, 一次一次会话可以包括多次请求
void removeAttribute(String name) // 删某一条信息
void invalidate() // 销毁整个Session
可以通过invalidate()实现安全退出
下面的代码就是销毁Session对象, 实现安全退出
public class DestroySessionServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取Session对象, 如果没有Session对象则返回null
HttpSession session = request.getSession(false);
if (session != null) {
// 销毁Session对象
session.invalidate();
}
}
}
8. HttpSession和HttpServletRequest接口的对比
1. 上面两个都是范围对象
HttpSession session; 是会话范围
HttpServletRequest request; 是请求范围
2. 两个范围的大小
session > request
3. 功能
session完成的是跨请求共享, 但是这些请求必须在同一个会话
request完成跨Servlet共享数据, 但是这些Servlet必须在同一个请求中(转发)
4. 使用原则
由小到大尝试, 优先使用小范围
例如: 登录成功之后, 已经登录的状态需要保存起来, 可以将登录成功的状态保存在session对象中