React+PostgreSQL注册功能报Failing row contains错误排查
错误含义
Failing row contains (43, ccc, null, 0, 2022-07-01 15:37:11.631)是PostgreSQL抛出的非空约束违反错误:你向users表插入数据时,某个设置了NOT NULL(不允许为空)且无默认值的字段被传入了null,数据库拒绝写入。括号内是本次尝试插入的行数据,按你建表的字段顺序排列,对应关系为:
43:自增主键id,数据库自动生成,无问题ccc:用户名name,正常传入null:触发报错的空值,对应email字段0:用户积分entries,建表时设置了默认值0,正常填充2022-07-01 15:37:11.631:注册时间joined,代码中传入了new Date(),无问题
根因定位
问题出在后端逻辑缺失+前后端传参不匹配,和React框架本身无关,核心问题有3个:
- 直接触发报错的原因:插入
users表时email字段值为null,要么是前端提交时漏传email参数,要么是传参格式错误导致后端未解析到email值 - 后端注册逻辑不完整:虽然从请求体中解构了
password参数,但既没有用bcrypt生成密码哈希,也没有向login表写入密码记录,就算本次约束报错修复,后续登录功能也无法正常运行 - 错误处理缺失:接口捕获到数据库错误后仅在控制台打印,没有给前端返回错误响应,导致前端页面无反馈
另外你的App.js中渲染Register组件时,两个props之间漏了空格,会导致组件props解析异常:
// 错误写法 <Register loadUser={this.loadUser}onRouteChange={this.onRouteChange}/>
修复步骤
1. 重写后端注册接口
替换原有/register接口代码,补全参数校验、密码哈希、事务写入、错误返回逻辑:
app.post('/register',(req,res)=>{ const{email,name,password}=req.body; // 前置校验,缺参数直接返回错误,避免请求打到数据库 if(!email || !name || !password){ return res.status(400).json('请补全全部注册字段'); } const hash = bcrypt.hashSync(password); // 使用事务保证users、login两张表数据一致性 db.transaction(trx => { trx.insert({ hash: hash, email: email }) .into('login') .returning('email') .then(loginEmail => { return trx('users') .returning('*') .insert({ email: loginEmail[0].email, name: name, joined: new Date() }) .then(user=>{ res.json(user[0]); }) }) .then(trx.commit) .catch(trx.rollback) }) .catch(err => res.status(400).json('注册失败,请检查输入信息')) })
2. 修复前端传参问题
- 首先修正App.js中Register组件的props写法,补上空格:
<Register loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
检查Register组件的提交逻辑,确保满足以下要求:
- 请求地址为
http://localhost:3000/register,不要漏写3000端口 - 请求头添加
'Content-Type': 'application/json' - 请求体用
JSON.stringify()转换,包含email、name、password三个字段,字段名不要拼写错误
标准提交逻辑参考:
- 请求地址为
onSubmitRegister = () => { fetch('http://localhost:3000/register', { method: 'post', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ email: this.state.email, password: this.state.password, name: this.state.name }) }) .then(response => response.json()) .then(user => { if(user.id){ this.props.loadUser(user) this.props.onRouteChange('home'); } }) }
3. 校验数据库表结构
打开PostgreSQL客户端确认两张表配置正确:
users表:id为serial自增主键,name、email为varchar类型且设置非空约束,entries为bigint类型默认值0,joined为timestamp类型设置非空约束login表:id为serial自增主键,email为varchar类型设置非空+唯一约束,hash为varchar类型设置非空约束
注:你当前的/signin、/image、/profile接口都在使用内存中的mock数据,没有操作数据库,注册功能修复后还需要同步改造这几个接口,否则登录、积分累加功能无法正常使用。
内容的提问来源于stack exchange,提问作者Ankit Dhanotia
相关产品推荐
相关产品推荐

