Express+GCloud应用Promise未处理警告及注册哈希异常求助
问题排查与修复方案
核心问题分析
注册接口:未解析Promise直接存入数据库
hashPass返回的是Promise对象,你直接把它赋值给userHash并插入Datastore,导致数据库存储的是Promise而非加密后的哈希字符串,这是插入报错的直接原因。登录接口:Promise同步判断逻辑错误
authUser中getUser(username)返回Promise,你直接访问.hash会得到undefined,因为Promise还未解析。同时登录接口里用const auth = authUser(...)后直接判断auth === false,这是同步逻辑,而auth实际是Promise对象,永远不会等于false,导致登录逻辑完全失效(只是看起来正常,实际根本没做验证)。未处理的Promise拒绝警告
部分catch块仅打印错误但未将错误传递出去,导致Promise被静默拒绝,触发unhandled promise rejection警告。
修复后的完整代码
var express = require('express'); var router = express.Router(); const {Datastore} = require('@google-cloud/datastore'); const datastore = new Datastore(); const bcrypt = require('bcrypt'); // 获取用户,返回用户对象(处理Promise解析) async function getUser(username){ try { const [user] = await datastore.get(datastore.key(['user', username])); return user; } catch (error) { console.error(error); throw error; // 抛出错误以便上层处理 } } // 验证用户,返回布尔值 async function authUser(username, password){ const user = await getUser(username); if (!user) return false; // 用户不存在直接返回false try { return await bcrypt.compare(password, user.hash); } catch (error) { console.error(error); throw error; } } // 加密密码,返回哈希字符串 async function hashPass(password){ try { return await bcrypt.hash(password, 10); } catch (error) { console.error(error); throw error; } } // 登录接口:改用async/await处理异步逻辑 router.post('/login', async function(req, res, next) { try { const isAuthenticated = await authUser(req.body.username, req.body.password); if (!isAuthenticated) { return res.redirect('/login'); } req.session.loggedIn = true; req.session.username = req.body.username; req.session.save(function(err) { if(err){console.error(err);} res.redirect('/users/show/'+req.body.username); }); } catch (error) { next(error); // 传递错误给Express错误处理中间件 } }); router.get('/logout', function(req, res, next) { req.session.destroy(function(err){ if(err){console.error(err);} res.redirect('/'); }); }); router.get('/signup', function(req, res, next){ res.redirect('/users/new'); }); // 注册接口:等待哈希生成后再插入数据库 router.post('/signup', async function(req, res, next) { try { if(req.body.notarobot !== "true"){ return res.redirect('/'); } if(req.body.password !== req.body.confirm){ req.session.error = "Passwords don't match"; console.error("Passwords don't match"); return res.redirect('/signup'); } // 等待密码哈希生成 const userHash = await hashPass(req.body.password); await datastore.insert({ key: datastore.key(['user', req.body.username]), data: { username: req.body.username, hash: userHash } }); console.log("successful entry"); req.session.loggedIn = true; req.session.username = req.body.username; req.session.save(function(err) { if(err){console.error(err);} res.redirect('/users/show/'+req.body.username); }); } catch (error) { console.error(error); if (error.code === 6) { // Datastore重复键错误码 req.session.error = "User already exists, choose a new username"; } else { req.session.error = "Registration failed, please try again"; } res.redirect('/signup'); } }); module.exports = router;
关键修复点说明
- 所有异步函数改用
async/await,让逻辑更清晰,避免Promise嵌套。 getUser中解构Datastore返回的数组(Datastore.get返回的是[实体, 响应]),之前的代码直接返回user会是包含实体的数组,导致后续取hash错误。- 所有
catch块在打印错误后抛出错误,确保Promise拒绝被上层处理,消除unhandled promise rejection警告。 - 注册接口中用
await等待hashPass完成,确保插入数据库的是哈希字符串而非Promise。 - 登录接口中等待
authUser的Promise解析,再进行判断,修复了之前同步判断的逻辑错误。 - 增加了Datastore重复键错误的判断(错误码6),更精准处理用户已存在的情况。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

