在网速慢的情况下,用户可能会重复提交表单;或者通过刷新来重复提交表单。在很多系统中是必须要避免重复刷新和重复提交的,以避免出现重复记录的问题。
解决重复提交的方案,可以在客户端,也可以在服务端。在客户端,可以通过js变量来标记用户是否提交过请求,若提交过,则不允许再次提交;但是在BS架构中,客户端的安全机制是不值得信赖的。安全可靠的处理须是在服务端进行。
在服务器端防止用户重复提交,就要标识用户的每一次页面请求,使得每一次访问都是唯一确定的。在服务器端处理页面请求时,可以生成一个标识本次请求的token,同时将token保存在session中,并将token信息以隐藏表单项返回给浏览器。
当用户提交表单时,服务器检查表单中的token和当前session中的信息是否一致。如果一致,说明没有重复提交,可以进行后续处理;处理之后当前token已失效,需要将当前token清除或更新当前token。
一个简单的实例如下:
//控制器(SpringMVC)
@Controller
public class UserController
{
@RequestMapping(value="/user/add",method=RequestMethod.GET)
public String addUser(HttpServletRequestrequest)
{
Random random=new Random();
Date date=new Date();
String token=date.getTime()+""+random.nextInt(1000);
request.getSession().setAttribute("token",token);
request.setAttribute("token",token);
return "addUser";
}
@RequestMapping(value="/user/add",method=RequestMethod.POST)
public StringaddUser(Stringname,String token,HttpServletRequestrequest)
{
if (token!=null&&token.equals(request.getSession().getAttribute("token")))
{
//token使用过后,需要更新或清除
request.getSession().removeAttribute("token");
request.setAttribute("info","添加成功");
}
else
{
request.setAttribute("info","已提交");
}
return"addUser";
}
}
//addUser.jsp
<%@ page language="java"contentType="text/html;charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%>
<!DOCTYPEhtml>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html; charset=UTF-8">
<title>添加用户</title>
</head>
<body>
<formaction="<%=basePath%>/user/add"method="post">
name:<inputtype="text"name="name"><br>
<inputtype="hidden"name="token"value="${token}">
<inputtype="submit"value="添加">
</form>
<scripttype="text/javascript">
var info="${info}";
if(info.length>0)
{
alert(info);
}
</script>
</body>
</ html >