多种方式防止表单重复提交

用户云卷云舒  金牌会员 | 2024-8-2 05:12:34 | 来自手机 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 553|帖子 553|积分 1659

1.前端方案:

通过js将按钮绑定一个方法,点击后3s内将按钮设置成不可用,或者隐藏。
缺点:绕过前端,例如通过postman发哀求。
2.hashmap版:

哀求携带一个参数,将哀求携带的参数(可以是用户id)存到内存的hashmap(用syc修饰)里,value存放哀求时间。
当下次发送哀求时,先判定map里有没有参数参数作为key。当哀求时先判定map里面有没有这个key,有并且时间凌驾3分钟就覆盖key,没有凌驾三分钟就返回哀求频繁。没有哀求成功。
缺点:随着时间推移map越来越大,oom。
3.commons-collections 轮子

Apache 为我们提供了一个 commons-collections 的框架,里面有一个非常好用的数据结构 LRUMap 可以生存指定数量的固定的数据,并且它会按照 LRU 算法,帮你扫除最不常用的数据。
  1. <dependency>
  2.         <groupId>org.apache.commons</groupId>
  3.         <artifactId>commons-collections4</artifactId>
  4.         <version>4.4</version>
  5. </dependency>
复制代码
  1. // 最大容量 100 个,根据 LRU 算法淘汰数据的 Map 集合
  2.     private LRUMap<String, Integer> reqCache = new LRUMap<>(100);
  3.     @RequestMapping("/add")
  4.     public String addUser1(String id) {
  5.         // 非空判断(忽略)...
  6.         synchronized (this.getClass()) {
  7.             // 重复请求判断
  8.             if (reqCache.containsKey(id)) {
  9.                 // 重复请求
  10.                 System.out.println("请勿重复提交!!!" + id);
  11.                 return "执行失败";
  12.             }
  13.             // 存储请求 ID
  14.             reqCache.put(id, 1);
  15.         }
  16.         // 业务代码...
  17.         System.out.println("添加用户ID:" + id);
  18.         return "执行成功!";
  19.     }
复制代码
思索:当采用分布式摆设,多台服务器上摆设项目,用户哀求时由于负载均衡、不知道哀求到那台服务器上了,上面的方法就不好用了。
4.分布式锁(用在多台服务器时,上面的方法用在单台服务器)

分布式锁就是对于一个对象只能有一个线程修改(对对象修改的方法只能有一个线程调用)。
基于数据库实现、redis实现、zookeeper实现
(1)数据库实现

存方法名、线程信息(设计可重入性)、失效时间(设置定时任务扫除,防止死锁)
   当执行某个方法时,将方法名和线程插入,插入前先查询是不是存在,存在就返回错误。不存在就插入。
  (2)redis实现



  • 将方法名和参数拼接作为key,uuid作为value,并设置有效时间(防止死锁)。利用setnx(如果不存在就存进入,如果存在就什么也不做)

  • 先判定redis中有没有key,如果有就是重复哀求,不做处理。
  • 如果redis中没有key,就不是重复哀求,执行业务。执行业务后,利用lua脚本释放锁。利用lua脚本,因为lua脚本在redis中以原子形式操作,要么全做,要么全不做。制止检查锁和删除锁引发的并发错误。
redis分布式锁方式,点击查看代码
(3)ZooKeeper实现分布式锁

ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目次树结构,规定同一个目次下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步调如下:
创建一个目次mylock;
线程A想获取锁就在mylock目次下创建临时顺序节点;
获取mylock目次下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当火线程顺序号最小,获得锁;
线程B获取所有节点,判定自己不是最小节点,设置监听比自己次小的节点;
线程A处理完,删除自己的节点,线程B监听到变动变乱,判定自己是不是最小的节点,如果是则获得锁。

这里保举一个Apache的开源库Curator,它是一个ZooKeeper客户端,Curator提供的InterProcessMutex是分布式锁的实现,acquire方法用于获取锁,release方法用于释放锁。
优点:具备高可用、可重入、壅闭锁特性,可办理失效死锁问题。
缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表