用户在页面上连续点击提交按钮,或者网络卡顿时反复刷新重试,是很多网站上线后常见的问题。一次操作变成两条订单、三条留言、五条报名记录,后台数据立刻变得难以核对。更麻烦的是,这些重复数据往往带着相同的时间戳和相近的内容,人工判断哪条有效、哪条该删,成本很高。要解决这个问题,不能只靠某一层加一个判断,而需要前端、网络、后端按顺序各管一段。
先分清三层各自该管什么
前端负责减少无效请求的产生,网络层负责应对传输过程中的意外重发,后端负责最终的数据一致性。顺序上应当从前到后依次设防:用户点击时先拦一道,请求发出后靠机制区分重复,数据落库前再做一次最终判断。如果顺序颠倒,比如只靠后端去重,用户仍会看到多次提交成功的反馈,体验和数据都会混乱;只靠前端置灰,一旦脚本被绕过或页面被刷新,重复请求照样会到达服务器。
前端置灰与令牌机制能挡住哪类重复
按钮点击后立即置灰或显示加载状态,是最直接的做法,能挡住同一页面内的连续点击。但它的边界也很明显:用户刷新页面、重新打开链接,或者在多个标签页同时操作,置灰就失效了。令牌机制则更进一步,页面加载时先向服务器申请一个一次性令牌,提交时随表单一起发送,服务器验证后立即作废。这样即使请求被重复发送,也只有第一次能通过。需要注意的是,令牌应当与当前会话或表单实例绑定,不能长期有效,也不要在前端缓存中反复复用同一个值。
后端幂等判断该以什么字段为依据
后端做最终判断时,不能简单用“内容相同”来判重,否则用户确实提交了两条相似但独立的留言就会被误伤。更稳妥的做法是让前端在提交时携带一个业务无关的唯一标识,由后端记录该标识的处理状态。同一个标识再次到达时,直接返回第一次的处理结果,而不是重新执行。判断字段应当选择那些真正代表一次操作的值,比如订单号、申请单号或提交序列号,而不是手机号、姓名这类可能被多人共用的信息。同时要设置合理的过期时间,避免标识长期占用存储。
一份可落地的自查清单
检查按钮在提交后是否立即进入不可点击状态,并给出明确的等待提示。确认令牌是否一次性使用,过期后能否正常重新获取。验证后端是否以唯一标识做幂等,而不是以内容比对。测试网络超时后自动重试的场景,看是否会产生第二条记录。检查重复请求返回时,前端是否显示与首次一致的结果,而不是报错。确认异常返回时,比如令牌失效或标识过期,用户能否得到清晰提示并重新提交。最后,用两个浏览器标签页同时提交同一表单,观察后台是否只产生一条有效数据。
涉及具体业务规则时,比如哪些字段可以合并、重复数据保留多久、是否需要人工审核,应当以实际系统设计和相关规范为准。防重复提交不是加一个按钮状态就结束,而是把校验顺序理清楚,让每一层只做自己该做的事。





