问题背景:
由于用户或网络延迟原因,用户在提交表单时会多次点击提交,此时表单内容会被多次提交给服务器。这样会资源的浪费。亟待解决。
表单重复提交类型:
1. 提交完表单以后,不做其他操作,直接刷新页面,表单会提交多次。
产生原因:
- 这种情况产生的根本原因是,Servlet处理完请求以后,直接转发到目标页面。
- 这样整一个业务,只发送了一次请求,那么当你在浏览器中点击刷新按钮或者狂按f5会一直都会刷新之前的请求
解决方案:
使用重定向跳转到目标页面
2. 在提交表单时,如果网速较差,可能会导致点击提交按钮多次,这种情况也会导致表单重复提交。 产生原因: 提交按钮可以点击多次。 解决方案: 使提交按钮只能点击一次。JS代码实现
window.onload = function(){
//获取按钮的对象
var btn = document.getElementById("sub_btn");
//为按钮绑定单击响应函数
btn.onclick = function(){
//点击以后使按钮不可用
this.disabled=true;
//当将提交按钮设置为不可用时,会自动取消它的默认行为
//手动提交表单
this.parentNode.submit();
};
};
3. 表单提交成功以后,直接点击浏览器上回退按钮,不刷新页面,然后点击提交按钮再次提交表单。 产生原因: 因为服务器在处理请求时,不会检查是否为重复提交的请求。 解决方案: **使用一个token的机制。** - token就是令牌的意思。 - 服务器在处理请求之前先来检查浏览器的token。 - token由服务器来创建,并交给浏览器,浏览器在向服务器发送请求时需要带着这个token - 服务器处理请求前检查token是否正确,如果正确,则正常处理,否则返回一个错误页面 - 服务器所创建的token只能使用一次。 - token一般使用一个唯一的标识。 具体解决流程: 1、生成一个token ``` <% //在服务器中生成一个token(一次性的令牌) String token = UUID.randomUUID().toString();
//在服务中保存token
session.setAttribute("token", token);
%>
${requestScope.contextPath }
注册页面
用户名 ``` 2、在servlet中进行令牌的对比 ``` //获取浏览器持有的token String reqToken = request.getParameter("token"); //获取session中保存的token
String sessToken = (String) request.getSession().getAttribute("token");
//将使用过的token从session中移除
request.getSession().removeAttribute("token");
//比较令牌是否一致
if(reqToken != null && reqToken.equals(sessToken)){
//令牌一致,处理请求
//获取用户名
String username = request.getParameter("username");
//将用户信息插入进数据库
System.out.println("已经将 "+username+" 插入进数据库!");
//重定向到regist-success.jsp
response.sendRedirect(request.getContextPath()+"/form/regist-success.jsp");
}else{
//重复提交的请求,重定向到一个错误页面
response.sendRedirect(request.getContextPath()+"/form/error.jsp");
}
![token机制图解](https://img-blog.csdn.net/20170812110038735?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjUzNDM1NTc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
<hr/>
Strusts2框架防止表单重复提交(套路)
----------------------
1、我们直接在表单中使用<font color="red"><s:token></s:token>标签</font>,它可以自动在表单创建一个表单隐藏域,并生成一个随机的token,同时它也会将该token放入到session域中。
2、使用拦截器可以在请求到达action之前来替我们验证token值。
Struts2框架提供了两种token拦截器-----token和tokenSession:
> 这两个拦截器检查token的机制相同,检查请求参数中的token和Session中token是否一致检查完毕之后都会从session中移除token
> 不同的是token 会在没通过验证时,将页面转到一个错误页面
> 而tokenSession会继续转到action执行完毕以后的页面,但是action并不会执行
<font color="skyblue">token</font>
-token拦截器,会在检查token错误时,将请求转到result的name为invalid.token的结果。
- 使用token拦截器之前,需要先在action中引入token拦截器
/token-error.jsp
<font color="skyblue">tokenSession</font>
-tokenSession拦截器在发现表单重复提交以后,并不会转到错误页面,而是继续返回执行成功页面,但是它不会执行action的方法
/success.jsp
/token-error.jsp