网购填地址、报名抢名额、提交维修申请……这些操作你肯定干过。可有时候手一快,连点两下“提交”按钮,结果订单生成了两单,或者客服收到两条一模一样的报修信息——不是系统出错,是表单被重复提交了。
为啥会重复提交?
说白了,就是用户没等到页面跳转或提示出现,下意识又戳了一次。网络稍慢、手机卡顿、老人看不清反馈,都容易触发。后端没做防护的话,请求就原样照收,数据就多了一条。
普通用户也能防:前端加个“小开关”
最简单有效的办法,是在点击提交后立刻禁用按钮,并改个文字:
<button id="submitBtn" type="submit">立即提交</button>加几行 JS 就能搞定:
document.getElementById('submitBtn').addEventListener('click', function(e) {
this.disabled = true;
this.textContent = '提交中...';
});这样点完第一下,按钮就灰了,再点也没反应,等页面跳转或提示出来,事儿就稳了。
更靠谱的组合拳:前后端一起守
光靠前端还不够,万一有人绕过 JS 直接发请求呢?所以后端得加个“令牌”机制(也叫 Token 机制):
1. 页面加载时,服务器生成一个一次性 token,写进表单隐藏域:
<input type="hidden" name="_token" value="abc123xyz">2. 提交时带上这个 token,后端校验它是否有效且未使用过;校验通过就处理请求,并立即将该 token 标记为“已用”。下次再拿同一个 token 来,直接拒绝。
这就像去菜市场买菜,摊主给你一张编号纸条,买完就撕掉,再拿同一张来,他不认。
居家小技巧:试试“时间戳+IP”轻量方案
如果你只是搭个简单的家庭预约表(比如预约智能音箱调试、共享打印机使用登记),不想搞复杂后端,可以用个土办法:
在提交前,用 JS 把当前时间戳和用户 IP(可用 navigator.userAgent + 时间拼个简易指纹)拼成一个哈希值,存在 sessionStorage 里;提交时附带这个值。后端收到后,检查最近 2 分钟内有没有相同指纹的请求,有就丢掉。
不完美,但对家里老人小孩日常用,够用了,也不用装额外服务。
表单不是越炫酷越好,而是让人安心、不犯错。把按钮变灰那一下,其实就是在说:“别急,我正在办。”