Heroku部署Vue+Node前后端分离应用偶现fetch请求重复插入MySQL记录问题
根因排查方向
首先明确:fetch标准规范本身没有自动重发POST请求的逻辑,偶发重复提交和本地不复发的特性,优先排查以下场景:
跨域CORS预检请求误判
后端如果没有正确区分OPTIONS预检请求和POST业务请求,可能会把预检请求也执行业务插入逻辑。要确认Express路由只处理POST方法的请求,且全局中间件没有在处理OPTIONS时误走到数据插入逻辑。
本地环境如果是前后端同端口调试或者没有跨域,不会触发预检,所以不会复现问题。交互逻辑触发多次请求
如果没有做提交防抖、按钮禁用处理,用户可能因为部署后页面响应慢于本地,多次点击提交按钮触发多次请求;另外Vue组件如果提交逻辑绑定的事件没有正确销毁、依赖项变化导致组件重复渲染,也可能重复执行请求逻辑。Heroku平台的请求重试机制
Heroku的路由层在后端实例响应超时(默认30秒超时)时,会自动将请求转发到其他可用实例重试,如果后端插入逻辑已经执行完但响应超时,重试的请求会再次插入数据。本地环境没有这层路由重试,所以不会复现。网络环境导致的自动重试
部分移动端浏览器、运营商网络在网络切换/波动时,会自动重试未完成的POST请求,也会导致重复提交。
修复方案
- 后端加幂等校验:前端提交时生成唯一的
requestId放在请求头或者请求体中,后端插入数据前先校验该requestId是否已经处理过,已经处理过直接返回成功结果,避免重复插入,这是解决重复提交最稳妥的方案。 - 前端加提交状态控制:点击提交后立刻禁用提交按钮,请求结束(无论成功失败)再恢复按钮可用状态,避免用户多次点击。
- 后端明确处理OPTIONS请求:在Express中添加全局中间件处理OPTIONS预检请求,直接返回204状态码,不要走到业务路由逻辑:
app.use((req, res, next) => { if (req.method === 'OPTIONS') { res.header('Access-Control-Allow-Origin', '*') res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS') res.header('Access-Control-Allow-Headers', 'Content-Type, Accept') return res.sendStatus(204) } next() }) - 添加请求日志:前后端都添加请求日志,记录请求的唯一标识、请求时间、请求方法,出现重复数据时直接对比日志就能定位是前端多发还是后端重试导致的问题。
内容的提问来源于stack exchange,提问作者Roberto Brizuela
相关产品推荐
相关产品推荐

