介绍
对于表单重复提交对于大家来说都不陌生,就是说当我们在进行表单提交时候,有可能出现网络延迟的情况,这个时候我们又点击按钮进行了表单的重复提交,对于以下的情况,我们可能就只是进行了两次的登录,对于这种情况问题还不是很大。
但是对于以下的情况,当我们在进行第一次转账时候,输入了密码,却发现并没有得到任何的响应,于是又进行了一次的转账,这个时候就可能会导致两次的转账的出现,这种情况来说是比较严重的。
对于重复提交我们也有一些的解决方案----前端验证:
- 就是在ajax提交之后把按钮给禁用掉,就是在没有得到响应之前,是不能够重复点击按钮的。
- 若是使用form表单进行提交,对于js提交表单之前将按钮禁用掉 。使用到的是disabled 属性。也能够防止表单的重复提交。
注意:但是以上的情况对于重复刷新页面,或者是使用url直接提交请求信息还是会出现问题。所以这里我们介绍一下对于使用token字符串进行验证提交。
token字符串
对于以下时序图我们进行讲解:
- 在页面提交请求之前,会先提交一个ajax请求(这个请求可以是我们自己定义,定义为在点击提交按钮之前就先进行一次提交请求,并将信息返回回来。),让后台系统生成一个UUID字符串作为令牌,同时保存到HttpSession中,最终这个HttpSession会返回给前端的页面。
- 在页面正式开始请求时候,不仅会带上必须要传递的信息,同时还会带上这个UUID字符串,后台会将HttpSession中保存的字符串与这一次请求时候上传的字符串进行一个比对,若是相等,表示是同一次的请求,就继续执行,同时会把HttpSession里面的令牌删除。然后执行正常的方法。
- 那么对于这种方法是如何防止表单的重复提交呢? 思考一下 对于我们在第一次提交的过程中,对于请求还没到达后台,此时用户又重复进行了页面的刷新,此时这次的请求正常请求到了后台并进行了响应,但是此时第一次请求到了,但是对于第一次请求的字符串和第二次正常请求的字符串并不相等,所以说服务器也并不会对携带这个字符串的请求进行响应,所以也就可以保证表单的重复提交。
编程实现
- 我们先创建一个用来生成token字符串的类来模拟在正式请求之前的token字符串的生成和删除。
@RestController
@RequestMapping("/token")
public class tokenController {
@RequestMapping("/save")
public R save(HttpServletRequest request){
HttpSession session=request.getSession();
String token= UUID.randomUUID().toString();
session.setAttribute("token",token);
return R.ok().put("token",token);
}
//R 是本项目自己封装的一个类 不用在意。
@RequestMapping("/remove")
public R remove(HttpServletRequest request){
HttpSession session=request.getSession();
session.removeAttribute("token");
return R.ok();
}
}
首先我们使用到postman来进行正式提交之前的提交获取token字符串的提交,可以看到的是,返回给我们正确的信息,这个token字符串我们会在下一次请求时候带上,同时也存在与Httpsession中。
- 下面来模拟测试一下:测试代码如下
- 首先判断给定的session中是否存在token 存在进行取出来,然后和上传的进行比对,若是不想等,表示不是同一次请求。
- 若是同一次请求,将token信息删除,返回正确的信息。
- 我们在测试时候发现,对于第一次的请求可以返回正确的信息,对于重复提交,因为token已经被删除,认定为第二次的提交,不进行处理。
@RestController
@RequestMapping("/test")
public class textController {
@RequestMapping("demo1")
public R save(HttpServletRequest request,
@RequestParam Map<String,Object> map){
HttpSession session=request.getSession();
String token="";
if(session.getAttribute("token")!=null){
token=session.getAttribute("token").toString();
}
if(!token.equals(map.get("token").toString())){
return R.error("token error");
}
session.removeAttribute("token");
// 写上自己的业务代码。
return R.ok();
}
}
点击第一次发起请求,因为我们的Httpsession中保存了对应的session,此时我们又进行一个上传,可以看到返回的是正确信息。
然后我们相同url点击第二次请求,发现请求出现错误
后记
对于我们第一次提交时候可能会出现网络延迟,用户刷新页面,重复提交,这个时候这个提交到达服务器,生成一个token信息保存在HttpSession中,然后用户正式提交表单等,发现此时提交带的token信息(是我们一次提交两次请求的第一次请求返回的token)和HttpSession中token信息相同(因为同时也保存在了Httpsession中),表示是同一次提交,后台进行处理,然后将token删除。当第一次提交到达服务端以后,发现的是此时的token信息和HttpSession信息不想等,或者说HttpSession中已经不存在token,就绝对不会将此次的提交给上传上去,就可以防止重复提交。以上就是模拟使用token来防止重复提交,这里也只是提供一个小小的思想,有什么错误的地方还望大家能够指证出来。