btn.addEventListener('click', async () => {
btn.disabled = true;
await fetch('/api/export', { method: 'POST', body: form });
});
运营在弱网下连点导出按钮,任务队列里出现 3 条相同记录,同一批数据发了三封邮件,附件大小一模一样。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。
原因不复杂,按钮只在请求返回后置灰,请求还没回来时仍可点击。后端没有幂等键,每次请求都当成新任务入队。
「导出重复提交」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。
一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。先做最小复现,能稳定跑出来的问题,排查成本会低一个数量级。
处理上按这个顺序:点击瞬间禁用按钮并显示进行中状态 失败再恢复;前端生成一次性 request_id 随请求带上;后端用 request_id 做唯一索引 重复请求直接返回已有任务。
改完只确认一件事:连点三次只产生一条任务记录,只收到一封邮件。
