会话控制
为什么要有会话控制呢?
HTTP协议两大缺陷:
无状态
纯文本
- 所谓的无状态就是指服务器不能区分出多次请求是否发送自同一个用户。
但是这里我们又希望服务器可以区分出不同用户发送的请求,所以这里我们就需要做会话控制。
- 去电影院看电影:
1.电影院印票
2.电影院发票
3.用户拿着票去看电影
4.电影院验票
- 我们可以不以给浏览器也发送一个“电影票”,当浏览器下次再访问服务器时,就可以带着这张“票”
然后我们的服务器就可以根据不同的票去识别不同的用户了。
1.会话控制第一节
[1] Cookie
> Cookie实际上就是一个头,服务器通过响应头的形式将Cookie发送给浏览器,
浏览器收到Cookie以后,将Cookie保存,在下次访问服务器时,会将Cookie以请求头的形式发回。
> Cookie就相当于服务器发送给浏览器的一张“票”
> Cookie由服务器创建,发送给浏览器。
浏览器收到Cookie以后,会将Cookie保存。
在之后的每次访问服务器时,都会携带着Cookie。
服务器就可以根据不同的Cookie的信息,去识别不同的浏览器。
>
1.服务器创建Cookie
2.将Cookie发送给浏览器
3.浏览器带着Cookie访问服务器
4.服务器检查浏览器的Cookie
> Cookie是通过响应报文发送给浏览器,Cookie实际上就是一个响应头:
形式如下:Set-Cookie: username=laosong
> 当浏览器收到这个响应头以后,会将Cookie的信息保存,并在之后访问中发回Cookie。
通过请求报文发送Cookie,形式如下:
Cookie: username=laosong
> 使用Cookie
- 创建Cookie
Cookie cookie = new Cookie(String name , String value);
- 发送Cookie
response.addCookie(cookie);
- 读取Cookie
Cookie[] cookies = request.getCookies();
- 修改Cookie
> Cookie一旦发送给浏览器,那么服务器就不能直接修改了。
但是可以通过使用同名Cookie来替换已有Cookie。
> Cookie的有效时间
- Cookie的默认有效时间为一次会话,一旦会话结束则浏览器会将Cookie销毁,下次访问服务器时将不再携带Cookie。
- 同样,我们也可以手动指定Cookie的有效时间:
- 我们可以通过cookie.setMaxAge()来设置Cookie的有效时间
该方法需要传一个秒数。
- 当我们传一个大于0的秒数时:
则Cookie的有效时间,会设置为相应的秒数
- 当我们传递一个等于0的秒数时,
则Cookie会立即失效,浏览器不会保存Cookie信息
- 当我们传递一个小于0的数时,
和没设置一样,Cookie关闭浏览器之后失效
- 设置一个永久有效的Cookie
cookie.setMaxAge(60*60*24*365*10);
> Cookie的Path
- Cookie的path就是Cookie的有效路径,指浏览器在访问哪些路径时会携带Cookie
- Cookie的默认有效路径是当前项目的根目录,只要是访问当前项目根目录下的资源,浏览器就会携带Cookie
- 我们可以通过cookie.setPath()来设置Cookie的有效路径
- cookie的路径由浏览器解析,所有设置路径时需要加上项目名
- 比如 cookie.setPath(request.getContextPath+"/hello")
这样我们Cookie的有效路径就是当前项目根目录下的hello,
那么只要访问hello这个目录下的资源就会带着Cookie
> Cookie的用途:
- 用户登录状态的保持
- 淘宝会保存用户的用户名
- 广告的推送
> 模拟一下淘宝的功能:
保存用户的用户名,用户登录成功一次以后,下次再登录时,直接将用户名显示
流程:
1.用户在login.jsp中输入用户名和密码
2.将请求提交给LoginServlet
3.LoginServlet检查用户名和密码是否正确
- 如果正确:
1) 将用户名保存到Cookie中,并将Cookie发送给浏览器
2) 重定向到login-success.jsp
- 如果错误:
1) 转发到login.jsp
4.下次用户再登录时,直接读取Cookie中的用户名,并将用户名回显
Cookie
Cookie实际上就是一个头,它由服务器创建并通过响应头的形式发送给浏览器,
浏览器保存Cookie后,每次会以请求头的形式将Cookie发回给服务器,
服务器就可以根据发回的Cookie来识别不同的浏览器。
Cookie的局限:
1.各个浏览器对Cookie的数量和大小都有不同的限制,所以不能在Cookie中保存过多的信息。
2.即使浏览器对Cookie不做限制,而浏览器每次访问服务器时会发回Cookie,会占用大量的带宽。
3.Cookie是纯文本的通过Http协议发送,本身也不太安全。
2.会话控制第二节
[1] HttpSession
> 简介
- HttpSession是JavaWeb中的一个域对象
- HttpSession的对象是保存在服务器中
- 浏览器的每一次会话,服务器都会创建一个HttpSession对象与之对应
- 每一个Session对象都有一个唯一的标识,我们创建session对象以后,只需要将该标记发送给浏览器
浏览器再次访问服务器时,只需要携带着该标识,服务器就可以根据该标记找到它对应的HttpSession对象
- Session的运行原理有点像银行卡,Session对象就相当于是一个账户,它是保存到服务器中的,
而session的id就相当于账户的账号,每一个账号都对应一个唯一的账号,同样每一个id都对应唯一的HttpSession对象
Session会以Cookie的形式发送给浏览器,浏览器会将Cookie保存,并在下次访问时携带,
这样服务器就可以根据浏览器携带的id,找到对应的HttpSession对象
服务器发送的Cookie,形式如下:
Set-Cookie: JSESSIONID=95AF9CCBED75BAE8D215CCDEBC235B34; Path=/12_WEB_Session
这个Cookie的name叫做JSESSIONID,value就是对应的HttpSession对象的id
浏览器会将id以如下形式发回:
Cookie: JSESSIONID=95AF9CCBED75BAE8D215CCDEBC235B34
- Session对象使用的唯一标识,实际是上使用的UUID
> 工作机制
- Session对象是在什么时候创建的?
- Session对象并不是浏览器以访问服务器就会创建,而是当getSession()方法第一次调用的时候创建。
1.当第一次调用getSession()方法时,服务器会创建一个新的HttpSession对象。
2.创建完对象以后,服务器会将HttpSession对象保存到一个SessionMap中,
这个map的key就是Session的id,而value就是session对象本身。
3.将Session的id以Cookie的形式发送给浏览器:JSESSIONID=...
4.浏览器会将Cookie保存,在下次访问时携带着该Cookie
5.当我们再次调用getSession()方法:
服务器会去检查浏览器是否携带JSESSIONID这个Cookie,
如果携带了则根据ID去SessionMap中寻找Session对象
如果没有携带JSESSIONID则重新创建一个Session对象
- 我们在访问JSP的时候也会创建Session对象,因为在JSP对应的Servlet中,已经自动调用getSession().
> 有效时间
- Session的默认有效时间是一次会话,也就是当我们关闭浏览器以后Session对象中的属性就获取不到了。
但是这种情况,并不是服务器中HttpSession销毁,而是浏览器保存的Cookie没了,
服务器不能通过id找到Session对象,就只能创建一个新的Session对象,于是老的Session对象中的属性就获取不到了。
- 我们可不以让Session对象在浏览器关闭之后依然有效呢?
- 我们只需要修改JSESSIONID这个Cookie的有效时间就可以了。
- 实际上我日常使用中没有什么实际意义
- 还有一种情况HttpSession对象超过一段时间没有使用,服务器也会自动销毁Session对象
这时即使浏览器带着JSESSIONID这个Cookie,也找不到Session对象,这时服务器也会创建一个新的Session对象
- 这个时间我们称为Session的最大闲置时间,一旦闲置超过这个时间,则Session对象会被销毁。
- 获取Session的最大闲置时间:
session.getMaxInactiveInterval(),获取session最大闲置时间,返回的是一个秒数
- 设置Session的最大闲置时间:
在总的web.xml文件有如下配置:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
它设置session的最大闲置时间为30分钟,我们可以通过修改该值的方式来修改默认的闲置时间,
如果我们通过总的web.xml修改,那么修改将会应用服务器中的所有项目。
如果我们只想对当前项目的Session进行修改,我们可以在当前项目的web.xml文件中修改
- 查询Session对象时否为新建的:
session.isNew() --> 返回一个布尔值,新建的返回true,不是新建的返回false
- 还可以直接去调用session的方法去设置:
setMaxInactiveInterval() 用来设置session的最大闲置时间,需要一个秒数
传一个大于0的数
> 则session闲置时间会设置为相应的秒数
传一个等于0的数
> 如果将session的闲置时间设置为0,则session对象会立即失效
> 如果想使session直接失效,也可以通过session.invalidate();
传一个小于0的数
> 如果设置一个小于0的数,则session永不失效。
> URL重写(了解)
- Session依赖于Cookie,所有如果浏览器禁用了Cookie,则session也就废了。
- 如果禁用了Cookie,则浏览器不会在请求报文中携带Cookie,这时我们也可以通过地址栏来发送Cookie信息
http://localhost:8080/项目名/请求地址;cookieName=cookieValue
如果要传送JSESSIONID这个cookie则需要这么写:
;jsessionid=F61AAF903C34D1D1F1E28EB0E512F045
- 我们可以通过response的两个方法来重写URL
encodeURL()
encodeRedirectURL()
这两个方法会自动为绝对路径加上JSESSIONID,如果浏览器禁用了Cookie,则自动加上,如果没禁用则不处理
- 我们还可以通过JSTL中c标签来重写URL地址:
<c:url value="/3.jsp"></c:url>
> Session的活化和钝化
- 钝化:
将HttpSession对象从内存中序列化到硬盘中的过程叫钝化。
在服务器停止时,会自动将Session对象钝化到硬盘中。
- 活化:
将硬盘中HttpSession对象反序列化到内存中的过程叫活化。
服务器启动时,会自动将硬盘上的Session对象活化到内存中。
- 注意:
一个类要想和Session一起钝化到硬盘中,该类必须要实现Serializable接口,
同时该类中的所有属性,也必须实现该接口
- 用途:
当服务器中存在的HttpSession对象过多时,如果这些对象都保存到内存中,那么会占用我们大量内存。
所以我们希望当Session对象闲置了一定时间以后,将内存中的对象钝化到硬盘中,
当用户再次需要使用时,在将对象活化回来吧。
要实现该功能,需要在服务器context.xml配置文件中加上如下的配置:
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="mySession" />
</Manager>
maxIdleSwap:最大的闲置时间,指当session对象闲置多久以后,就钝化到硬盘中
directory:Session钝化到的目录
> 表单的重复提交
- 将相同的表单的信息多次提交到服务器。
- 表单重复提交的危害:
1.表单重复提交时,提交都是重复的数据,将重复的数据插入进数据库,会造成数据库中的垃圾数据过多。
2.重复提交数据,可能不是用户的主观意愿,可能会对用户造成损失
3.大量处理重复的数据,会占用服务器的资源,影响服务器的性能。
- 第一种情况:
表单提交成功以后,反复刷新成功页面,会造成表单的重复提交
- 产生的原因:
我们操作成功以后,使用转发的形式跳转到成功页面,而使用转发时,浏览器只发送了1次请求,
所以提交成功以后再次刷新页面时,还是刷新的提交表单的那次请求。
- 解决:
使用重定向跳转到成功页面
- 注意:由于转发时有表单重复提交的问题,所以我们目前来讲能用重定向就不用转发。
- 第二种情况:
当网速比较慢时,提交表单后没有立即跳转页面,这时点击多次提交按钮,也会造成表单的重复提交
- 产生的根本原因:
提交按钮可以点击多次
- 解决:
使按钮只能点击一次,点击一次以后让按钮失效
window.onload = function(){
//获取id为sub_btn的按钮
var btn = document.getElementById("sub_btn");
//为btn绑定单击响应函数
btn.onclick = function(){
//使按钮失效
//可以通过disabled属性来设置一个对象是否可用
//如果设置一个true则失效
//如果设置一个false则有效
this.disabled = true;
//当我们将提交按钮失效以后,部分浏览器将默认不提交表单
//需要手动提交表单
this.parentNode.submit();
};
};
- 第三种情况:
当提交表单成功以后,点击回退按钮,而不刷新页面,再次提交请求也会造成表单的重复提交
- 产生的根本原因:
服务器会处理重复提交的请求,服务器不能识别请求是否为重复提交的请求
- 解决方案:
引入token机制,token就是令牌的意思。
所谓的Token就是,由服务器创建一个一次性的令牌,并将令牌交给浏览器,
浏览器会将令牌和请求一起提交,服务器在处理请求之前,先检查浏览器的令牌,
如果令牌正确才处理请求,如果令牌错误则跳转到一个错误页面。
令牌实际就是一个唯一的标识,使用UUID即可
- 如何使用:
1.在服务器中生成一个token(UUID)
2.服务器将token保存到Session中
3.将token保存到表单的隐藏域中
4.用户提交表单,token和请求参数一起提交到服务器
5.比较session中的token和request请求参数中的token是否一致
- 如果一致,处理请求
- 否则,转到一个错误页面,不处理请求
6.将session中的token移除
session的运行流程
![](https://images2015.cnblogs.com/blog/1033125/201610/1033125-20161025153146515-1988895644.png)
转载请注明出处!
http://www.cnblogs.com/libingbin/
感谢您的阅读。如果文章对您有用,那么请轻轻点个赞,以资鼓励。