JavaWeb——会话控制

一、会话控制简述
 HTTP协议是一个无状态协议,我们的服务器不能区分多次请求是否发送自同一个浏览器。
 我们可以使用Cookie来解决这个问题。Cookie的工作机制:Cookie实际上就是一个头(请求头或者响应头),服务器以响应头的形式将Cookie发送给浏览器, 浏览器接收到该头以后,会将Cookie的信息保存,然后在每次访问服务器时,会以请求头的形式再将该Cookie发送给服务器。
 Cookie的局限性:
  1️⃣Cookie是纯文本,非常容易被截获,不太安全
  2️⃣各个浏览器对Cookie的数量和大小都有限制,也就是说我们不能在Cookie中保存过多的信息
  3️⃣即使对Cookie大小没有限制,我们也不会在Cookie中保存大量信息,因为浏览器每次访问时都会发回Cookie,这样会占用大量带宽
 我们还可以使用Session来进行会话控制,Cookie和Session同属于会话控制的范畴。

二、HttpSession
 HttpSession运行时依赖于Cookie,因为JSESSIONID是通过Cookie传递的,session是JavaWeb中的四个域对象之一。由于Cookie中的信息是保存在浏览器端的,浏览器每次访问时都需要发回Cookie,所以我们不能在Cookie中保存大量的信息。既然客户端不能保存大量的信息,那可不可以将信息保存到服务器端呢?我们可以为每次会话都在服务器中创建一个对象,然后在该对象中保存相关的信息。这个对象就是HttpSession,那怎么给会话和对象建立一个对应关系呢?给每一个session对象都赋有一个id,这个id是不可重复的,也就是每一个Session对象都有一个唯一的标识。这样我们就可以将这个唯一的标识交个浏览器保存,浏览器每次访问服务器时都会带着这个唯一标识(即JSESSIONID),这样服务器就可以根据这个唯一标识找到每个会话对应的session对象了。
 SESSION工作机制:HttpSession对象就相当于浏览器在服务器的账户,而session的id(JSESSIONID),相当于这个账户的账号。实际上HttpSession对象就是服务器中用来保存会话信息的对象,每个session对象都有一个唯一的id,这个id通过cookie的形式先由服务器发送给浏览器,浏览器收到cookie以后会自动保存,然后在每次访问服务器时,都会带着这个Cookie,服务器就可以根据Cookie中保存的session的id找到浏览器对应的session对象。
 Cookie的具体形式如下:

Set-Cookie JSESSIONID=A1C1D6E213BDF1F147E673963ED503B2

 一次会话对应一个session对象,那session对象是什么时候创建的呢?HttpSession对象是在调用getSession()方法时创建的,但并不是第一次调用setSession()时都会创建session,会根据是否有JSESSIONID这个Cookie以及这个Cookie的状态来判断是否创建session(JSESSIONID存在且有效时不新创建,否则新建)。HttpSession创建时会有一个JSESSIONID,服务器会将session对象保存到一个SessionMap中,这个map的key就是JSESSIONID,而value就是session对象。如果浏览器在访问服务器时携带JSESSIONID这个Cookie,服务器就不会再去创建新的Session对象,而是根据浏览器的JSESSIONID的值,去SessionMap中查找已有的Session对象。在JSP对应的Java文件中已经自动调用getSession()方法,所以我们在访问JSP时也会创建session对象,这也是session是jsp页面中的隐藏对象的原因。
在这里插入图片描述
 session的默认有效时间为一次会话,session的默认时间之所以是一次会话,并不是因为HttpSession对象被销毁,而是因为浏览器中保存JSESSIONID的那个Cookie的默认有效时间为一次会话,Cookie的销毁导致JSESSIONID的丢失。
 HttpSession对象都是保存到服务器的SessionMap中的,一旦Session对象闲置超过一定时间以后,服务器会自动将该对象销毁,那这样以后即使浏览器还保存着JSESSIONID,但是由于对象已经销毁了,所以这时服务器要重新创建一个新的HttpSession对象。判断sesseion是否是新建的:

session.isNew();

 如何设置Session的最大闲置时间?
  1、我们可以通过修改tomcat的web.xml配置文件的方式:
   在tomcat的web.xml文件中有如下配置信息:将session的默认闲置时间设置为30分钟

<session-config>
	<session-timeout>30</session-timeout>
</session-config>

  我们可以通过修改该值,来修改session的有效时间,这会导致当前服务器下的所有项目的session的闲置时间都会被修改。
  2、在当前项目的web.xml文件中设置,设置方法和上边一样:

<session-config>
	<session-timeout>30</session-timeout>
</session-config>

  3、可以通过调用session对象方法的形式来设置:

session.setMaxInactiveInterval(秒数);

session.invalidate();//使session立即失效

   大于0的时间:会设置闲置时间为相应的秒数
   等于0的时间:会使session对象立即失效
   小于0的时间:如果给setMaxInactiveInterval方法设置一个负的时间,则session对象永远不会被销毁,除非手动调用session.invalidate()方法
  我们可以通过session.getMaxInactiveInterval()来获取session的最大闲置时间。
Tip:较为安全的Cookie和Session的校验方式是,在对Cookie或Session进行校验时同时校验请求的IP。例如,我们可能会在Session中存放当前登录用户的对象信息user,那可以在封装user对象时同时添加一个登录IP的属性,并在用户登录成功时设置该IP属性的值,这样在通过JSESSIONID获取到session对象以后,先判断该session是否为新建session(session.isNew()),如果不是新session再比对请求的IP和session中存放的user对象的IP是否一致,一致则通过校验,否则校验失败,获取IP的方式参考如下:

public static String getIpAddress(HttpServletRequest request) {  
	String ip = request.getHeader("x-forwarded-for");  
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
		ip = request.getHeader("Proxy-Client-IP");  
	}  
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
		ip = request.getHeader("WL-Proxy-Client-IP");  
	}  
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
		ip = request.getHeader("HTTP_CLIENT_IP");  
	}  
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
		ip = request.getHeader("HTTP_X_FORWARDED_FOR");  
	}  
	if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
		ip = request.getRemoteAddr();  
	}  
	return ip;  
}  

三、URL重写
 HttpSession运行时依赖于Cookie,如果我们将浏览器的Cookie禁用,那么HttpSession将不能正常使用,因为浏览器如果禁用了Cookie则无法保存携带着JSESSIONID的那个Cookie,也就是说浏览器每次访问服务器时候都无法携带JSESSIONID,而每次都会新建一个Session对象,所以Session对象将不能正常使用。
 之前我们的Cookie都是通过请求报文的请求头来传送,我们可不可以通过URL地址来传递JSESSIONID呢?比如:

http://localhost:8080/12_WEB_Session/hello.jsp?jsessionid=29BAA3DDCCD6563ECE852D78E76EDC54

 这种方式就叫做URL重写,但是我们手动拼地址很不靠谱,可以通过调用response的方法,以下两种方式得到的url就是url重写之后的结果:

String url = response.encodeURL(request.getContextPath()+"/hello.jsp");
String url2 = response.encodeRedirectURL(request.getContextPath()+"/hello.jsp");

 还可以通过JSTL中的url标签,这种方式更简便:

<c:url value="/hello.jsp"></c:url>

 整体来说URL重写比较简单,但是我们在实际开发中对URL重写做的并不是很多,一般情况下如果浏览器将Cookie禁用,那么一些依赖于Session的功能也将失效:因为Cookie和Session中都携带了一些个人信息,URL重写以后的地址,容易泄露信息,不太安全。

四、Session的活化和钝化
 钝化是指将HttpSession对象序列化到硬盘中,一般钝化发生在服务器停止时。服务器停止时会自动将HttpSession对象序列化到硬盘,这个过程我们称为钝化。
 活化是将硬盘中HttpSession对象加载进内存中,一般在服务器启动时,会自动将硬盘中HttpSession对象重新加载进内存。
 一个类要想可以序列化到硬盘中必须要实现java.io.Serializable接口,这个类中的所有属性也需要实现java.io.Serializable接口,在开发时大部分类都要实现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的最大闲置时间,超过该时间以后,session将会自动钝化
 directory:钝化到硬盘中的目录
 session会钝化到tomcat服务器的work目录中

五、表单的重复提交
 表单重复提交指的是同一个表单相同的内容多次提交。
 表单重复提交的危害:
  1️⃣增加数据库中垃圾数据
  2️⃣无形中增加了服务器压力
 表单重复提交的几种情况:
  1️⃣表单提交成功以后,反复刷新成功页面
   产生原因:使用的是转发。我们在Servlet中使用转发的形式跳转到成功页面,整个过程中浏览器只发送了一次请求,当我们在成功页面刷新时,实际是将上次的请求又发送了一遍,所以造成了重复提交。
   解决:不使用转发,而是使用重定向。重定向发了两次请求,我们再次刷新,刷新的是第二个请求,而不是第一个。
  2️⃣网速较慢时,用户多次点击提交按钮。
   产生原因:就是表单的提交按钮可以点击多次
   解决:使表单的提交按钮只能点一次,点完一次以后按钮将变为不可用的状态。

window.onload = function(){
	//点击完提交按钮以后,让按钮变为一个不可用的状态
	//获取按钮对象
	var btn = document.getElementById("btn");
	//为按钮绑定一个单击响应函数
	btn.onclick = function(){
		//设置按钮为不可用状态
		this.disabled = true;
		//如果将按钮设置为不可用状态,那么表单也将不会提交
		//我们需要手动提交表单
		this.parentNode.submit();
	};
};

  3️⃣成功提交请求后,点击回退按钮,但是不刷新页面,再次提交。
   产生原因:服务器端的Servlet不能区分两次请求是不是重复提交的内容
    解决:在Servlet中,在处理请求之前,先来检查表单是否是重复提交。使用token解决这个问题。
   token是令牌的意思,token就是一串随机码。所谓的token就是服务器在处理用户请求之前,先检查token是否正确,如果token正确那服务器正常处理请求;如果token不正确服务器不处理请求。我们的令牌是一个一次性的令牌,只能使用一次,所以使用完毕之后一定要将token销毁
   流程:使用UUID创建token,令牌一定要销毁不销毁是起不到作用的
    1️⃣创建一个令牌,要求唯一,不能重复(UUID),并在服务器中保存token
    2️⃣将token放入到浏览器的表单中
    3️⃣浏览器提交表单时,会同时将token一起提交
    4️⃣服务器在处理请求之前要检查令牌是否有效
    5️⃣销毁token
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值