使用Joi做用户校验时触发Cannot read property 'string' of undefined错误如何解决
问题修复方案
1 错误原因梳理
- 初始
TypeError: Cannot read property 'string' of undefined报错:你安装的@hapo/joi为非官方兼容包,导出规则与官方Joi不一致,导致引入的joi变量为undefined,调用joi.string触发属性读取报错。 - 改后
password: Path password is required报错:存在三处核心错误:- Joi校验方法使用错误:官方Joi v16+版本使用
schema.validate(data)的方式调用校验,而非joi.valid(data, schema),valid是枚举值校验的内置方法,不用于全局schema校验 - 校验方法引入错误:校验文件导出的是包含
userValidation属性的对象,你直接将整个导出对象赋值给userValidation变量,调用时没有取到实际的校验方法,导致输入校验失效 - 新用户实例赋值错误:加密后的密码存储在局部变量
hashedPassword中,你错误从req.body.hashedPassword取值,导致存入数据库的password字段为undefined,触发mongoose的必填校验
- Joi校验方法使用错误:官方Joi v16+版本使用
2 修正代码
2.1 修正校验文件(validation.js)
//validation const joi = require('joi'); // 用户创建校验规则 const userValidation = (data) => { const schema = joi.object({ username: joi.string().min(6).required(), password: joi.string().min(6).required(), // 新增二次密码校验逻辑,适配前端表单的password2字段 password2: joi.string().valid(joi.ref('password')).required().messages({'any.only': '两次输入密码不一致'}) }); return schema.validate(data); }; // 登录校验规则 const loginValidation = (data) => { const schema = joi.object({ username: joi.string().min(6).required(), password: joi.string().min(6).required() }); return schema.validate(data); }; // 导出校验方法 module.exports.userValidation = userValidation; module.exports.loginValidation = loginValidation;
2.2 修正createUser回调的引入和赋值逻辑
const expressValidator = require('express-validator'); // 修正拼写错误:原bycrypt为笔误,正确包名为bcrypt const bcrypt = require('bcryptjs'); const bodyparser = require("body-parser"); const passport = require('passport'); const flash = require('express-session'); // 修正引入:解构取出导出对象里的userValidation方法 const { userValidation } = require('./validation'); // 若之前未引入userSchema请补充:const userSchema = require('../models/你的user模型文件路径'); exports.createUser = async(req, res, next) => { console.log('Post CREATE User /create-user'); // 校验用户输入 const { error } = userValidation(req.body); // 校验不通过时返回错误 if (error) { return res.status(400).send(error.details[0].message); } try { // 检查用户是否已存在 const userExist = await userSchema.findOne({ username: req.body.username }); if (userExist) return res.status(400).send('UserName Already Exist'); // 密码哈希处理 const salt = await bcrypt.genSalt(10); const hashedPassword = await bcrypt.hash(req.body.password, salt); // 修正赋值:直接使用局部变量hashedPassword,不需要从req.body取值 const user = new userSchema({ username: req.body.username, password: hashedPassword }) // 将用户数据存入数据库 await user.save(); res.redirect('/halalMunchies/all-employees'); } catch (error) { console.log(error); res.status(500).send({ message: error.message || "Some error occured while creating user" }); } };
3 额外配置确认
请确认express入口文件已经配置了body-parser的表单解析中间件,否则req.body无法读取到表单提交的内容:
app.use(bodyparser.urlencoded({ extended: false })); app.use(bodyparser.json());
内容的提问来源于stack exchange,提问作者Hesham Eldawy
相关产品推荐
相关产品推荐

