表单防止重复提交处理的前后台十种处理方法

背景

       软件系统可能会因为网络、电脑、系统本身等原因导致的页面响应慢。这个时候为了避免用户重复点击,我们需要防止用户重复提交来避免业务/系统数据异常。

 重复提交(简单)提示效果

前端控制(辅助手段)

【方法一】按钮状态控制

用户点击后立即禁用提交按钮或置灰,配合加载动画提示操作状态。该方法仅能减少误操作,无法防御恶意请求‌

const handleSubmit = () => {
  setButtonDisabled(true); // 禁用按钮
  // 发送请求
};

【方法二】变量标记法控制

  var submitFlag = false;//防重复提交标志
  //表单提交函数
  publishA=function(){
	  ....... // 校验逻辑(如果有)
      if(!submitFlag)// 没有提交过才提交
      {
	     submitFlag = true;
         document.addform.submit();// 提交
         // 其他实现可使用类似方式让提交按钮在单击后灰掉
         // document.addform.disabled=true;
      }
      else
      {
         alert("请不要重复提交!");
      }
  }

【方法三】防抖与节流技术

通过限制高频点击(如1秒内仅允许提交一次),降低重复提交概率‌

特性防抖节流
触发逻辑延迟执行,以最后一次触发为准固定间隔执行,忽略中间触发
适用场景需等待操作停止的场景(如输入停止)‌需均匀分配触发次数的场
  1. 原生JS实现‌:推荐封装通用函数,支持参数化延迟时间和立即执行选项‌。
  2. Vue项目集成‌:使用工具库(如 js-tool-big-box)快速调用防抖与节流方法,减少重复代码‌。
  3. React Hooks‌:结合 useCallback 和 useRef 管理定时器状态,避免组件重复渲染‌

 后端核心防御

【方法四】‌Token令牌机制

服务端生成唯一令牌(如UUID)并存储于Session/Redis,表单提交时校验令牌有效性,处理后立即销毁。可有效拦截重复请求‌

// Java示例:生成并校验Token
String token = UUID.randomUUID().toString();
session.setAttribute("formToken", token);

程序流程图 

 【方法五】session变量控制

较token令牌机制简单,在session中记录页面的提交状态
jsp页面

  //设置标志变量SubmitFlag值
  session.putValue("SubmitFlag","complaint_add.jsp");

control层:

 public String addxxx(){
		String PageFlag="";
		HttpSession session;
		session = getSession(true);
		PageFlag=(String) session.getValue("SubmitFlag");
		if (PageFlag.equalsIgnoreCase("Over")){
			//repeatSubmit
			return "XXX";
		}
	  session.putValue("SubmitFlag","Over");
	  .......
  }

或者:

在服务器端生成一个独一无二的标识符,并将其存入Session中。同时,这个标识符会被写入表单的隐藏字段内。当用户填写完信息并点击提交后,服务器会获取表单中隐藏字段的值,并与Session中的唯一标识符进行比对。如果两者相等,则正常处理该请求;如果不相等,则说明是重复提交,服务器将不再对其进行处理‌ 

‌【方法六】‌幂等性设计

通过业务唯一标识(如订单号)或数据库唯一约束,确保多次相同请求仅产生一次效果。适用于支付、订单等场景‌

ALTER TABLE orders ADD UNIQUE (order_no); -- 数据库唯一约束

【方法七】请求参数校验

记录请求关键参数(如用户ID+时间戳),短时间内重复参数直接拦截‌

数据库层加固

【方法八】唯一索引约束

对关键字段(如手机号、邮箱)添加唯一索引,从存储层拦截重复数据。需配合异常处理优化用户体验‌

其他补充方案

‌【方法九】POST-REDIRECT-GET模式

提交后重定向至结果页,避免浏览器刷新导致重复提交‌。

‌【方法十】分布式锁

在微服务架构中,通过Redis分布式锁控制并发请求,确保全局唯一性‌

AOP注解化集成(进阶实践)

自定义注解
定义 @NoRepeatSubmit 注解,支持配置锁超时时间和需校验的请求参数‌。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmit {
    int expire() default 3;   // 锁超时时间(秒)
    String[] params() default {}; // 参与生成Key的请求参数名
}

切面逻辑
在AOP切面中解析注解,动态生成锁Key并控制加锁/解锁流程‌。

@Around("@annotation(noRepeatSubmit)")
public Object around(ProceedingJoinPoint joinPoint, NoRepeatSubmit noRepeatSubmit) {
    String key = generateLockKey(joinPoint, noRepeatSubmit.params());
    try {
        if (!tryLock(key, noRepeatSubmit.expire())) {
            return Result.error("重复提交");
        }
        return joinPoint.proceed();
    } finally {
        releaseLock(key);
    }
}
场景策略
高并发表单提交结合AOP注解 + 参数级锁粒度 + 200ms随机重试间隔‌。
短时高频操作设置更短超时时间(如1秒),结合前端按钮禁用降低后端压力‌。
分布式集群环境使用Redisson或RedLock算法,通过多节点多数派机制提升可靠性‌。

结语:作者建议

实际项目中大家用的前后台技术多种多样,这里作者只是举个例子,说明场景及解决方案的逻辑。在实际项目中读者根据实现情况可选用一个或多个。

附件一:幂等和防重对比

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞火流星02027

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值