在说明处理方案前,我们先来列举一下有哪些情况会出现表单重复提交的情况,接着我们从客户端到服务端的顺序逐一说明处理方案。
- 多次点击提交按钮
- 提交表单后,点击浏览器的后退按钮
- 使用浏览器的历史记录重复提交表单
- 点击浏览器的刷新按钮
若有读者发现仍有其它重复提交表单的情况,欢迎留言提出,谢谢。
客户端角度
- 在提交表单后,使用JS将提交按钮disable。这种方法可以防止用户多次点击提交按钮,但若是客户端禁止了js或者用户知道表单提交的地址以及表单的结构,自行生成表单进行重复提交,该方法也就无效了。
- 在请求表单页面时,服务端生成一个能够标识的特殊标志串,存在Session中,并放在表单的隐藏域里。服务端接收处理表单数据时,检查标识串与Session中的标识串是否一致,若一致表明是首次提交,则立即从哪Session中删除,然后正常处理数据,否则不再处理。
- 使用Cookie记录表单提交的状态,根据其状态可以检查是否已经提交表单。若客户端禁止了Cookie,该方法将不起作用。
服务端角度
- 使用Post/Redirect/Get模式,简单来说就是提交表单后,执行一次客户端的重定向,转到提交成功信息提示页面。这种方式能够避免客户重复按刷新和点击后退按钮导致的重复提交表单。
- 在数据库里添加唯一约束或者创建唯一索引,防止出现重复数据。这也是一种防止重复提交表单数据的方式。
a.表单提交“请求”到servlet后,servlet再将“请求”转发到一个jsp页面,在响应页面点击刷新。分析:点击刷新时,地址栏中的URL还是原来的请求输入的地址,点击刷新后,就是发出再一次的请求,所以表单重复提交。
b.当有网络延迟,或者线程阻塞的情况下,在响应页面没有到达时,重复点击提交按钮。分析:很明显,浏览器发出了多次请求,表单重复提交。
c.在响应页面,点击返回,再点击“提交”。分析:和a其实是一个效果
如何避免表单的重复提交
a.在表单中:
<body>
<%
//在原表单页面,生成一个token随机值,
String tokenValue=new Date().getTime() +"";
%>
<form method="post" action="/SuccessServlet">
<%
//把token放入session中
session.setAttribute("token",tokenValue);
%>
<input type="hidden" name="token" value=<%=tokenValue %>/>
name:<input type="text" name="name"/>
<input type="submit" value="提交"/>
</form>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
b.在servlet中:
HttpSession session = request.getSession();
Object token = session.getAttribute("token");
String tokenValue = request.getParameter("token");
if(token.equals(tokenValue) &&token != null){
session.removeAttribute("token");
}else{
response.sendRedirect(request.getContextPath()+"/error.jsp");
}