HTTP POST请求重复提交导致数据库产生多条重复注册记录如何解决
问题原因
- 前端事件重复绑定:从代码的JSX结构可判断为React组件,你直接在组件渲染逻辑中通过
addEventListener给form绑定提交事件,若组件重渲染(状态更新、父组件重渲染触发)或React 18严格模式下开发环境的两次挂载逻辑,都会重复绑定registerUser回调,一次提交操作会触发多次请求。同时你未在组件卸载时移除事件监听,也会加剧该问题。 - 无提交状态限制:没有添加提交中拦截逻辑,用户快速点击提交按钮、或网络卡顿时重复点击,都会触发多次请求。
- 服务端无唯一性校验:数据库未对用户名字段设置唯一校验规则,重复的注册请求都会被成功插入,最终产生多条重复数据。
解决方案
前端修复
- 替换原生事件绑定为React内置的
onSubmit属性,从根源避免重复绑定问题,同时移除原有addEventListener相关代码:
<FormContainer id="reg-form" onSubmit={registerUser}>
- 添加提交状态锁,拦截重复提交,同时可把提交按钮置灰提升用户体验:
import { useState } from 'react'; // 组件内添加提交状态 const [isSubmitting, setIsSubmitting] = useState(false); async function registerUser(event){ event.preventDefault(); // 提交中直接拦截后续请求 if(isSubmitting) return; setIsSubmitting(true); const username = document.getElementById('username').value; const password = document.getElementById('password').value; const data = { username, password }; const options = { method: 'POST', headers: { 'Content-Type':'application/json' }, body: JSON.stringify(data) }; try{ const fetchResponse = await fetch('https://alfred-cipher-5000.codio-box.uk/api/register', options); const resData = await fetchResponse.json(); // 可在此处添加提交成功后的逻辑(如跳转、清空表单) return resData; } catch (e) { return e; } finally { // 请求结束后重置提交状态 setIsSubmitting(false); } } // 提交按钮添加禁用状态 <Input type="submit" autoComplete="off" value="Submit Form" disabled={isSubmitting}/>
服务端修复
增加用户名唯一性校验,即使前端出现漏判,也不会插入重复数据:
app.post('/api/register', (request, response)=> { console.log('new request'); const data = request.body; // 先查询是否已有相同用户名 database.findOne({username: data.username}, (err, doc) => { if(err) return response.status(500).json({error: '数据库服务异常'}); if(doc) return response.status(400).json({error: '该用户名已注册'}); // 无重复数据再执行插入 database.insert(data, (err, newDoc) => { if(err) return response.status(500).json({error: '注册失败,请重试'}); response.json(newDoc); }); }); });
内容的提问来源于stack exchange,提问作者Daniel Dias
相关产品推荐
相关产品推荐

