Joi v13升级至^17后验证失效及未处理Promise拒绝问题求助
解决Joi v17升级后
schema.validate报错及请求挂起问题 我刚帮你定位到问题所在了,主要有两个关键点导致了这个错误和请求挂起的情况:
1. schema.validate的参数传递错误
Joi v17中,schema.validate()的正确签名是schema.validate(value, [options]),第二个参数是可选的配置对象(比如{ abortEarly: false }这类验证选项),而不是你代码里传的schema本身。你写的schema.validate(req.body, schema)把schema当成了选项参数传入,直接触发了Joi内部的Invalid message options错误,这也是服务器报错的根源。
2. 未处理的Promise拒绝
你的CreateUser是async函数,但schema.validate抛出的错误没有被try/catch捕获,加上异步操作里的未处理rejection,导致请求一直挂起,服务器抛出UnhandledPromiseRejectionWarning。
修复后的完整代码
下面是修正后的代码,我还把bcrypt.hash改成了promise形式,保持async/await的统一风格,避免回调嵌套,也更容易处理错误:
const Joi = require("@hapi/joi"); const HttpStatus = require("http-status-codes"); const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); const User = require("../models/userModels"); const Helpers = require("../Helpers/helpers"); const dbConfig = require("../config/secret"); module.exports = { async CreateUser(req, res) { try { const schema = Joi.object().keys({ username: Joi.string() .min(5) .max(10) .required(), email: Joi.string() .email() .required(), password: Joi.string() .min(5) .required() }); // 修正validate参数:第二个参数不传或传配置选项,不是schema const { error, value } = schema.validate(req.body); if (error && error.details) { return res.status(HttpStatus.BAD_REQUEST).json({ msg: error.details }); } const userEmail = await User.findOne({ email: Helpers.lowerCase(req.body.email) }); if (userEmail) { return res .status(HttpStatus.CONFLICT) .json({ message: "Email already exist" }); } const userName = await User.findOne({ username: Helpers.firstUpper(req.body.username) }); if (userName) { return res .status(HttpStatus.CONFLICT) .json({ message: "Username already exist" }); } // 改用async/await处理bcrypt.hash,避免回调嵌套 const hash = await bcrypt.hash(value.password, 10); const body = { username: Helpers.firstUpper(value.username), email: Helpers.lowerCase(value.email), password: hash }; const user = await User.create(body); const token = jwt.sign({ data: user }, dbConfig.secret, { expiresIn: "5h" }); res.cookie("auth", token); res .status(HttpStatus.CREATED) .json({ message: "User created successfully", user, token }); } catch (err) { // 统一捕获所有异步错误 console.error(err); if (err.message === "Error hashing password") { return res.status(HttpStatus.BAD_REQUEST).json({ message: err.message }); } res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ message: "Error occured" }); } } };
关键修改点说明
- 把
schema.validate(req.body, schema)改成schema.validate(req.body),如果需要配置验证规则(比如允许所有错误都返回,而不是遇到第一个就停止),可以传{ abortEarly: false }作为第二个参数 - 用
try/catch包裹整个异步逻辑,统一处理所有可能的错误,避免未捕获的Promise拒绝 - 将
bcrypt.hash的回调形式改成await调用,让代码更简洁易读,也便于错误捕获
这样修改后,你的POST请求应该就能正常处理,不会再出现挂起和报错的情况了。
内容的提问来源于stack exchange,提问作者Jazzman
相关产品推荐
相关产品推荐

