Sequelize ^6.6.5搭配bcrypt ^5.0.1实现密码哈希时报错求助
报错根因
报错信息明确指向bcrypt.hashSync的入参不符合要求:第一个参数password必须为字符串或Buffer类型,你当前的请求中req.body.password大概率是undefined、null、数字等非合法类型。同时你未给异步方法加异常捕获逻辑,才会抛出未处理的Promise拒绝警告。
解决方案
1. 增加请求参数校验
在加密逻辑前先校验密码参数合法性,避免非法入参传入bcrypt。
2. 改用bcrypt异步API
异步API不会阻塞Node.js事件循环,更符合Node.js开发规范,配合async/await语法使用体验更好。
3. 补充异常捕获逻辑
给控制器方法增加try/catch块,捕获业务逻辑中的异常,避免未处理的Promise报错。
4. (可选)将加密逻辑下沉到模型层
使用Sequelize的beforeCreate钩子自动处理密码加密,控制器无需感知加密逻辑,代码更易维护。
修改后的代码示例
控制器代码(UserController.js)
const User = require('../models/User'); const bcrypt = require('bcrypt'); module.exports = { async store(req, res) { try { const { name, age, city, email, password } = req.body; // 新增参数校验 if (!password || typeof password !== 'string') { return res.status(400).json({ error: '密码为必填参数,且必须为字符串类型' }); } // 改用异步hash方法,不需要单独生成salt,直接传rounds即可 const hash = await bcrypt.hash(password, 10); const user = await User.create({ name, age, city, email, password: hash }); // 不要返回密码字段到前端 const userWithoutPassword = user.toJSON(); delete userWithoutPassword.password; return res.json(userWithoutPassword); } catch (err) { return res.status(500).json({ error: '用户创建失败', detail: err.message }); } }, async index(req, res) { try { const users = await User.findAll({ attributes: { exclude: ['password'] } // 查询时排除密码字段 }); return res.json(users); } catch (err) { return res.status(500).json({ error: '用户列表查询失败', detail: err.message }); } }, async findById(req, res) { try { const { id } = req.params; const user = await User.findByPk(id, { attributes: { exclude: ['password'] } }); if (!user) { return res.status(404).json({ error: '用户不存在' }); } return res.json(user); } catch (err) { return res.status(500).json({ error: '用户查询失败', detail: err.message }); } }, };
(可选)新增模型钩子后的User模型代码
如果你选择把加密逻辑放到模型层,控制器可以不用处理加密逻辑,模型代码修改如下:
const { Model, DataTypes } = require('sequelize'); const bcrypt = require('bcrypt'); class User extends Model { static init(sequelize) { super.init({ name: DataTypes.STRING, age: DataTypes.INTEGER, city: DataTypes.STRING, email: DataTypes.STRING, password: DataTypes.STRING, }, { sequelize, hooks: { beforeCreate: async (user) => { if (user.password) { user.password = await bcrypt.hash(user.password, 10); } } } }) } static associate(models) { this.hasMany(models.Post, { foreignKey: 'user_id', as: 'posts' }); } } module.exports = User;
这个方案下控制器的store方法里不需要再手动处理密码加密,直接把原密码传给User.create即可,模型会自动完成加密。
额外验证步骤
如果修改后仍然报错,可以在加密逻辑前打印req.body和password的值,确认前端传参是否正确,是否存在拼写错误(比如前端传的是pwd而不是password)。
内容的提问来源于stack exchange,提问作者user11240162
相关产品推荐
相关产品推荐

