防止表单重复提交的几种方案

738 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情

防止表单重复提交的几种方案

介绍

表单重复提交是我们在开发软件过程中经常会遇到的问题,例如在提交订单,新增用户数据等等情况下,我们都要保证接口的幂等性,否则可能会出现点击两次,提交了两个订单,保存了两组用户数据。所谓幂等性,也就是一个接口,同一个请求多次调用时,接口执行并返回的结果是正确的,不能出现扣款时多次扣款,订单时多次提交相同订单等错误情况。

解决办法

  1. 前端通过js或者相关组件禁止一些操作,例如在提交、保存按钮点击之后,立即将按钮置灰或者隐藏,不可点击。
  2. 页面重定向,在提交、保存之后,页面重定向到保存成功、提交成功等页面,避免用户使用浏览器刷新等操作进行重复提交。
  3. 在session中存储标识位,在用户新增表单时,服务器端生成一个标识位,存入session中,并且传到前端,放在表单的隐藏字段中,在表单提交时,判断隐藏字段中的值和session中的标识位是否一致,如果一致,则认为是第一次提交,处理请求,处理完成之后,删除session中的标识位,如果不一致,则不处理请求。
  4. 使用乐观锁,在数据库中增加version版本号,每次修改数据时,version版本号都会加1,在重复提交时,第二次修改操作就会失败,修改不成功。
  5. 使用悲观锁,使用for update操作数据,for update是一种行级锁,在用户对数据加锁之后,只能查询,不能更新操作,是以独占方式锁表,在高并发的情况下,会导致问题,并且有可能会导致死锁,性能上也有问题,在实际开发中,不推荐使用。
  6. 在后端结合redis进行判断,在方法执行前,我们先根据参数和方法名计算出key,然后判断key是否存在,如果存在,则说明正在执行,返回报错信息,如果不存在,将计算出来的对应的key存入redis中,并且设置过期时间,标记该请求正在执行。此时redis中的key在过期之后才会删除,如果方法执行时间过长,需要设置合理的的过期时间。如果需要主动删除redis中key,可以考虑使用redis的分布式锁来实现。

小结

解决表单重复提交的方法有很多,除了上面的几种方式,我们还可以通过HashMap存储业务ID,使用Synchronized加锁等方式,每一种都有利有弊,需要根据实际业务场景进行选择。