我正在为ExpressJS应用程序中的Bookshelf用户模型添加一个非常基本的登录方法,但是我无法从被拒绝的承诺中捕获用户模型中的登录功能返回的错误。我正在查看Bookshelf在http://bookshelfjs.org/#Model-static-extend文档中的示例登录,但该示例使用Bluebird,而我正在尝试使用内置的ES6承诺执行相同的操作。
我在用户模型中的登录方法:
userModel.js
function login(email, password) {
return new Promise((resolve, reject) => {
User.where('email', email)
.fetch({ require: true })
.then(user => {
bcrypt.compare(password, user.get('password'), (err, matched) => {
if (!matched) return reject(new Error('Password didn\'t match!'));
resolve(user);
});
});
});
从Bookshelf User.login
模型实现登录和调用User
的控制器操作:
usersAuthController.js
function logUserIn(req, res) {
new User().login(req.body.email, req.body.password)
.then(user => res.json({ message: 'Login succeeded!' }))
.catch(User.NotFoundError, () => res.status(404).json({ error: 'User not found!' }) // catch #1
.catch(err => res.status(401).json({ err: err.message })); // catch #2
}
我的意图是,当Bookshelf的User.fetch
方法找不到具有给定电子邮件的用户时,login()
可以返回被拒绝的承诺。在这种情况下,.catch(User.NotFoundError ...)
(catch#1)行应该捕获它并返回404.当login()
确定密码传递给{时,我还打算bcrypt
返回被拒绝的Promise。 {1}}与用户的密码不匹配,在这种情况下,login()
catch语句下面的“catch-all”(catch#2)应返回401。
如果我输入了错误的密码,上面代码中的User.NotFoundError
控制器操作将捕获#2,错误消息为logUserIn()
,而不是我拒绝的消息{ error: "Cannot set property 'message' of undefined" }
消息在'Password didn't match!'
。如果我输入不存在的电子邮件,则永远不会发送响应,并且控制台中会抛出错误login()
。只有有效的输入才有效。
尝试修复:直接在模型中捕获Unhandled rejection CustomError: EmptyResponse
。
我将catch#1移到User模型,以便登录方法现在看起来像:
userModel.js
User.NotFoundError
这样,我可以正确捕获错误(错误的密码和不存在的电子邮件),但这样我就无法在控制器中指定状态代码。如果找不到具有给定电子邮件的用户,那么它应该返回404,但是如果密码不正确,那么它应该返回401,但是两个错误都会返回到catch-all(catch#2)控制器动作(总是返回401)。
要解决这个问题,在function login(email, password) {
return new Promise((resolve, reject) => {
User.where('email', email)
.fetch({ require: true })
.then(user => {
bcrypt.compare(password, user.get('password'), (err, matched) => {
if (!matched) return reject(new Error('Password didn\'t match!'));
resolve(user);
});
})
.catch(User.NotFoundError, () => reject({ error: 'User not found!' }));
});
模型中,我可以User
,在控制器操作中,我可以检查.catch(User.NotFoundError, () => reject({ name: 'NotFoundError', message: 'User not found!' }))
我遇到的错误类型但是看起来似乎非常混乱,并忽略了这些const statusCode = err.name === 'NotFoundError' ? 404 : 401
陈述的重点。
有没有办法从模型的登录方法中捕获.catch
以及User.NotFoundError
中的所有其他错误?为什么我最初没有使用的设置,在usersAuthController.js中同时包含logInUser
个语句的设置,以及catch
和Cannot set property 'message' of undefined'
错误的含义是什么(它有什么意义吗?将书架的蓝鸟承诺与内置的ES6承诺相混淆吗?处理这个问题的最佳方法是什么?
答案 0 :(得分:1)
在您的初始实施中,您不会传播可能由User.fetch()
引起的任何拒绝。另外,因为User.fetch()
已经返回了一个promise,所以用一个新的promise包装它是一种反模式(虽然你仍然需要用bcrypt.compare()
包含一个promise,因为它只适用于回调)
试试这个:
function login(email, password) {
return User .where('email', email)
.fetch({ require: true })
.then(user => {
return new Promise((resolve, reject) => {
bcrypt.compare(password, user.get('password'), (err, matched) => {
if (err) return reject(err);
if (!matched) return reject(new Error('Password didn\'t match!'));
resolve(user);
});
})
});
}