web开发会话技术-Session
Session是什么
- Session是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session对象/集合
- 由于session为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的session中读取/添加数据,从而完成相应任务
理解Session
- 你可以把session看作是一容器类似HashMap,有两列(K-V),每一行就是session的一个属性。
- 每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)
Session常用方法
API | 解释 |
---|---|
request.getSession() | 第1次调用是创建Session 会话,之后调用是获取创建好的Session对象 |
session.setAttribute(String name,Object val); | 向session添加属性 |
session.getAttibute(String name) | 从session得到某个属性 |
session.removeAttribute(String name) | 从session删除某个属性 |
session.isNew() | 判断是不是刚创建出来的 |
session.getId() | 获得sessionId(唯一标识Id值) |
Session创建流程
- 浏览器A请求服务端时,并获取Session
- 服务端执行getSession(),如果发现该浏览器没有对应的Session对象,就会在内存中创建一个和
浏览器A本次会话关联
的Session对象(key-value),并分配SessionId
● 这个session只属于浏览器A
● 只与本次会话有关联:当会话结束(浏览器关闭)或者session超过了存活时间,下次获得Session就会重新创建 - 获得Session后(无论是新Session还是原本存在),可以对Session进行一些操作(crud)
- 当浏览器访问服务端其他资源时,服务端就可以通过浏览器发送过来的
JsessionId
在内存中获取到与当前浏览器
关联的Session对象,进行操作(一个浏览器对应一个Session) - 当有其他浏览器请求服务端,服务端就会重新创建与该浏览器对应的Session对象,对其使用
服务端如何通过浏览器找到对应Session
- 浏览器向服务器发出请求
- 服务端接收到请求后,会执行
getSession()
- 判断浏览器是否带有
JsessionID
● 如果没有携带JsessionID
,那么会创建Session对象,并分配sessionID
,在内存中布局<sessionID,session对象>
● 如果携带JsessionID
,会判断在内存中是否有与sessionID=JsessionID
对应的session对象
○ 如果没有对应的session对象,那么会创建Session对象,并分配sessionID
○ 如果有对应的session对象,直接操作session对象 - 如果这次会话,创建了session对象,则会将sessionID以cookie的方式(
Set-Cookie: JessionID = xx
)发送给浏览器 - 浏览器接收到cookie后,会将JsessionID保存到浏览器内存
- 当下次浏览器再次访问该服务端时,会将JessionID带上,通过http请求发送给服务端(
Cookie: JSESSIONID=xx
)
Session生命周期
- public void setMaxInactiveInterval(int interval)设置 Session的超时时间(以秒为单位),超过指定的时长,Session就会被销毁。
- 值为正数的时候,设定Session 的超时时长。
- 负数表示永不超时
- public int getMaxInactiveInterval();获取Session的超时时间
- public void invalidate(); 让当前Session会话立即无效
- 如果没有调用setMaxInactiveInterval()来指定Session的生命时长,Tomcat会以Session默认时长为准,Session默认的超时为30分钟,可以在tomcat的web.xml设置
- Session的生命周期指的是﹔客户端/浏览器两次请求最大间隔时长,而不是累积时长。即当客户端访问了自己的session,session的生命周期将从0开始重新计算。(指的是同一个会话两次请求之间的间隔时间)
- 底层:Tomcat用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁
在session生命周期内,如果有至少一次访问服务端,那么session的存活时间将被刷新,从最近一次访问的时间开始计算,也就是 最近一次访问session时间 + session设置的过期时间 = session死亡时间
最近一次访问session时间 : 浏览器再访问服务端时,服务端调用了getSession()
方法
tomcat在启动时,会启动一个线程,这个线程的作用就是查看各个session对象是否过期
- 服务端在保存session对象时,会将session对象的最近一次访问时间和存活时间记录下来,线程会每隔一段时间,扫描所有session对象,如果发现
最近一次访问session时间 + session设置的过期时间 > 当前时间
,那么线程就会删除这个session,当浏览器要调用这个session对象,就只能重新创建。 - session的生命周期:两次访问session的最大间隔时间,也就是说,只要浏览器两次访问服务端的时间没有超过设置的过期时间,那么该cookie会一直存活下去(最近一次访问时间在不断的刷新)
- session是否过期,取决于服务器是否还存在这个session对象。就算浏览器还保留着过期的JsessionID,只要访问服务端,服务端就会创建一个新的session对象,并把新的sessionID返回给浏览器,浏览器便会更新JsessionID
Session的作用
Session基本原理
当用户访问服务端,并操作session时,服务端就会在(服务端)内存配置一个session对象,该session对象是用户当前这个浏览器独享,当用户访问当前服务端的其他的网页时,服务端就会根据JSESSIONID(用户第一次访问服务端就会从服务端传回来一个JSESSIONID cookie对象)来查找对应的session对象,根据需要来读取Session对象中的数据来为用户提供服务
Session可以做什么
理解Session
Session常用方法
Session底层机制分析
Session创建流程
- 浏览器A请求服务端时,并获取Session
- 服务端执行getSession(),如果发现该浏览器没有对应的Session对象,就会在内存中创建一个和
浏览器A本次会话关联
的Session对象(key-value),并分配SESSIONID
● 这个session只属于浏览器A
● 只与本次会话有关联:当会话结束(浏览器关闭)或者session超过了存活时间,下次获得Session就会重新创建 - 获得Session后(无论是新Session还是原本存在),可以对Session进行一些操作(crud)
- 当浏览器访问服务端其他资源时,服务端就可以通过浏览器发送过来的
JSESSIONID
在内存中获取到与当前浏览器
关联的Session对象,进行操作(一个浏览器对应一个Session) - 当有其他浏览器请求服务端,服务端就会重新创建与该浏览器对应的Session对象,对其使用
服务端如何通过浏览器找到对应Session
- 浏览器向服务器发出请求
- 服务端接收到请求后,会执行
getSession()
- 判断浏览器是否带有
JsessionID
● 如果没有携带JsessionID
,那么会创建Session对象,并分配sessionID
,在内存中布局<seeionID,session对象>
● 如果携带JsessionID
,会判断在内存中是否有与sessionID=JsessionID
对应的session对象
○ 如果没有对应的session对象,那么会创建Session对象,并分配sessionID
○ 如果有对应的session对象,直接操作session对象 - 如果这次会话,创建了session对象,则会将sessionID以cookie的方式(
Set-Cookie: JessionID = xx
)发送给浏览器 - 浏览器接收到cookie后,会将JsessionID保存到浏览器内存
- 当下次浏览器再次访问该服务端时,会将JessionID带上,通过http请求发送给服务端(
Cookie: JSESSIONID=xx
)
创建Session实例分析
CreateSession
public class CreateSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取session,同时也可能创建session
HttpSession session = request.getSession();
//2.给session获取id
System.out.println("当前session" + session.getId());
//3.给session存放数据
session.setAttribute("email","px@qq.com");
}
浏览器携带JsessionID,服务器内存中不存在该ID的session
这个JsessionID是在tomcat启动,默认访问的首页时,给浏览器发送了一个
但在服务端是不存在与这个JsessionID对应的session对象
访问http://localhost:8080/cs/CreateSession
请求头携带了JsessionID
服务端判断浏览器是否携带JsessionID-->
携带JsessionID-->
判断该JsessionID是否有对应的session对象-->
没有对应的session对象-->
创建session对象,并分配sessionID-->
服务端将sessionID封装为cookie对象,并返回给浏览器-->
浏览器保存(替换)JsessionID
查看后端 发现与发送的JsessionID确实是一样
浏览器携带JsessionID,服务器内存中存在该ID的session
浏览器带有上次访问浏览器的JsessionID
访问http://localhost:8080/cs/CreateSession
服务端判断是否浏览器是否携带JsessionID-->
携带JsessionID-->
判断该JsessionID是否有对应的session对象-->
有对应的session对象-->
直接操作session对象
只有创建了session对象,服务端才会返回JsessionID
并没有发生变化
浏览器没有携带JessionID
浏览器不存在JessionID
访问http://localhost:8080/cs/CreateSession
没有携带JessionID
服务端判断是否浏览器是否携带JsessionID-->
没有携带JsessionID-->
创建session对象,并分配sessionID-->
服务端将sessionID封装为cookie对象,并返回给浏览器-->
浏览器保存JsessionID
与后端一致
读取Session实例分析
ReadSession
public class ReadSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示读取session
//1.获取session,如果没有session,也会创建
HttpSession session = request.getSession();
//2.读取属性
Object email = session.getAttribute("email");
//3.获取id
System.out.println("ReadSession 当前sessionId: " + session.getId());
if (email != null) {
System.out.println("session属性email=" + (String) email);
} else {
System.out.println("session没有email属性");
}
}
http://localhost:8080/cs/createSession
在服务端创建与此浏览器对应的Session,并分配SessionID -->
将SessionID封装到http响应包中的Cookie-set(Cookie-set: JessionID=xxx
)响应头中,返回给浏览器-->
浏览器保存JessionID
http://localhost:8080/cs/readSession
将jessionID发送给浏览器
响应头没有返回JsessionID,证明找到了JessionID对应的session
查看后端,证明是同一个Session
Session生命周期
tomcat会起一个线程,来轮询每个session的上一次的会话时间,如果当前时间 -
上一个会话时间 >
设置的存活时间,那么会直接删除掉这个session
Session实例应用举例
createSession2
public class CreateSession2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//创建cookie
HttpSession session = request.getSession();
//设置生命周期 - 30秒
session.setMaxInactiveInterval(30);
System.out.println("createSession2 SID: " + session.getId());
//写入数据
session.setAttribute("job", "java");
}
readSession2
public class ReadSession2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Session
HttpSession session = request.getSession();
System.out.println("readSession2 SID: " + session.getId());
//读取Session属性
Object job = session.getAttribute("job");
if(job != null){
System.out.println("读取到session属性 job=" + (String)job);
} else {
System.out.println("读取不到session属性 job,说明原来的session被销毁");
}
}
http://localhost:8080/cs/createSession2
浏览器并没有携带JsessionID,因此服务器创建了session对象(设置存活时间: 30秒
),并将sessionID传回给浏览器
获取到了的JsessionID为A2F7E09286F59D8DC12981D42D4AAD52
在30秒内,去访问http://localhost:8080/cs/readSession2
将上次访问服务端获得的JessionID以cookie的形式发送给服务端
发送给服务端的JessionID为A2F7E09286F59D8DC12981D42D4AAD52
可以发现,服务端并没有发送新的JsessionID过来,证明获取到了session对象
此后30秒内,没有在对服务端进行访问
30秒后,再次访问http://localhost:8080/cs/readSession2
将上次访问的JsessionID以cookie的形式发送给服务端
发送给服务端的JessionID为A2F7E09286F59D8DC12981D42D4AAD52
发现响应包里,有一个响应头为Set-Cookie: JSESSIONID=776ACB536D6AA99C6C2B7D1995592139; Path=/cs; HttpOnly
证明上一个session已经过期,服务端在getSession()
时,找不到浏览器发送过来JessionID对应的session对象-->
自然会创建一个新的session对象-->
并将session对象对应的sessionID包装成cookie的形式,发送给浏览器-->
浏览器保存(替换)JsessionID
在这30秒,如果有至少一次访问服务端,那么session的存活时间将被刷新,从最近一次访问的时间开始计算,也就是 最近一次访问session时间 + session设置的过期时间 = session死亡时间
最近一次访问session时间 : 浏览器再访问服务端时,服务端调用了getSession()
方法
tomcat在启动时,会启动一个线程,这个线程的作用就是查看各个session对象是否过期
- 服务端在保存session对象时,会将session对象的最近一次访问时间和存活时间记录下来,线程会每隔一段时间,扫描所有session对象,如果发现
最近一次访问session时间 + session设置的过期时间 > 当前时间
,那么线程就会删除这个session,当浏览器要调用这个session对象,就只能重新创建。 - session的生命周期:两次访问session的最大间隔时间,也就是说,只要浏览器两次访问服务端的时间没有超过设置的过期时间,那么该cookie会一直存活下去(最近一次访问在不断的刷新)
- session是否过期,取决于服务器是否还存在这个session对象。就算浏览器还保留着过期的JsessionID,只要访问服务端,服务端就会创建一个新的session对象,并把新的sessionID返回给浏览器,浏览器便会更新JsessionID
Session生命周期-删除
deleteSession
public class DeleteSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示如何删除session
HttpSession session = request.getSession();
System.out.println("DeleteSession 的ID 为 " + session.getId());
session.invalidate();
}
访问:http://localhost:8080/cs/createSession
,服务端创建session对象,浏览器获得JsessionID
访问:http://localhost:8080/cs/readSession
,读取存放与session的值,是可以正常读取到的
访问:http://localhost:8080/cs/deleteSession
,删除浏览器发送来的JsessionID
访问:http://localhost:8080/cs/readSession
,读取存放与session的值,此时,与浏览器发送来的JsessionID:51FE5D359F8A4ADAF160F761BCB08B14
对应的session对象已经被删除,所以当调用getSession
方法时,是会重新创建一个session,并把sessionID发送给浏览器
Session经典案例–防止非法进入管理页面
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录界面</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/cs/loginCheckServlet" method="post">
用户名: <input type="text" name="username"><br/>
密 码: <input type="password" name="pwd"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
error.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>失败界面</title>
</head>
<body>
<h1>登录失败</h1>
<a href="/cs/login.html">点击返回重新登录</a>
</body>
</html>
LoginCheckServlet
package com.study.session.HW;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @author 珀筱
*/
public class LoginCheckServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pwd = request.getParameter("pwd");
String username = request.getParameter("username");
HttpSession session = request.getSession();
if ("123".equals(pwd)) {
session.setAttribute("login", "yes");
session.setAttribute("username", username);
// request.getRequestDispatcher("/manageServlet").forward(request, response);
response.sendRedirect("/cs/manageServlet");
} else {
session.setAttribute("login", "no");
// request.getRequestDispatcher("/error.html").forward(request, response);
response.sendRedirect("/cs/error.html");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ManageServlet
package com.study.session.HW;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 珀筱
*/
public class ManageServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("MangeServlet()...");
//获得session,用于该用户验证成功
HttpSession session = request.getSession();
Object login = session.getAttribute("login");
if (login != null && "yes".equals((String)login)) {
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
Object username = session.getAttribute("username");
writer.print("<h1>欢迎你管理员 " + (String) username + "</h1>");
writer.flush();
writer.close();
} else {
// request.getRequestDispatcher("/login.html").forward(request, response);
response.sendRedirect("/cs/login.html");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
cookie与session的区别
- cookie与session共同之处:cookie和session都是用来跟踪浏览器用户身份的会话方式。
- cookie是保存在浏览器内存中,而session是保存在服务端
- cookie中的数据在浏览器中是可以修改的,因此不安全,而session虽然安全,但如果访问量过多,会占用大量的服务器资源
- session中保存的是对象,cookie中保存的是字符串