使用 ES6 promises 和 BookshelfJS 捕获错误
Catching errors with ES6 promises and BookshelfJS
我正在向 ExpressJS 应用程序中的 Bookshelf 用户模型添加一个非常基本的登录方法,但我无法从用户模型 returns 中的登录功能被拒绝的承诺中捕获错误.我正在 http://bookshelfjs.org/#Model-static-extend 的文档中查看 Bookshelf 的登录示例,但该示例使用的是 Bluebird,而我正在尝试对内置的 ES6 promises 做同样的事情。
我在用户模型中的登录方法:
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);
});
});
});
从书架User
模型实现登录和调用User.login
的控制器动作:
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()
可以 return 拒绝承诺。在那种情况下,.catch(User.NotFoundError ...)
(catch #1) 行应该捕获它并且 return 一个 404。我还打算 login()
到 return 当 bcrypt
确定传递给 login()
的密码与用户的密码不匹配,在这种情况下 User.NotFoundError
catch 语句下面的 "catch-all" (捕获 #2)应该 return a 401.
如果我输入的密码不正确,上面代码中的 logUserIn()
控制器操作会使用错误消息 { error: "Cannot set property 'message' of undefined" }
而不是消息 'Password didn't match!'
来捕获 #2我在 login()
中拒绝了。如果我输入一个不存在的电子邮件,则永远不会发送响应,并且会在控制台中抛出错误 Unhandled rejection CustomError: EmptyResponse
。只有有效的输入才有效。
尝试修复: 直接在模型中捕获 User.NotFoundError
。
我将第一个问题移到了用户模型中,这样登录方法现在看起来像:
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);
});
})
.catch(User.NotFoundError, () => reject({ error: 'User not found!' }));
});
通过这种方式,我可以正确捕获这两个错误(密码不正确和电子邮件不存在),但是这样我无法在控制器中指定状态代码。如果找不到具有给定电子邮件的用户,那么它应该 return 一个 404,但是如果密码不正确,那么它应该 return 一个 401,但是这两个错误都会出现 -控制器操作中的所有(捕获#2)(始终 returns a 401)。
为了解决这个问题,在 User
模型中我可以做 .catch(User.NotFoundError, () => reject({ name: 'NotFoundError', message: 'User not found!' }))
并且在控制器操作中我可以检查 const statusCode = err.name === 'NotFoundError' ? 404 : 401
我遇到了什么样的错误但是这看起来真的很乱,并且错过了这些 .catch
语句的要点。
有没有办法从模型的登录方法中捕获 User.NotFoundError
以及 logInUser
中的任何其他错误?为什么我一开始的设置不起作用,usersAuthController.js 中有两个 catch
语句,Cannot set property 'message' of undefined'
和 CustomError: EmptyResponse
错误意味着什么(它有与混淆 Bookshelf 的 Bluebird 承诺与内置 ES6 承诺有关)?处理此问题的最佳方法是什么?
在您的初始实施中,您没有传播任何可能由 User.fetch()
引起的拒绝。此外,因为 User.fetch()
已经 returns 一个承诺,用一个新的承诺包装它有点反模式(尽管你仍然需要用一个承诺包装 bcrypt.compare()
,因为那只是与回调一起工作)。
试试这个:
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);
});
})
});
}
我正在向 ExpressJS 应用程序中的 Bookshelf 用户模型添加一个非常基本的登录方法,但我无法从用户模型 returns 中的登录功能被拒绝的承诺中捕获错误.我正在 http://bookshelfjs.org/#Model-static-extend 的文档中查看 Bookshelf 的登录示例,但该示例使用的是 Bluebird,而我正在尝试对内置的 ES6 promises 做同样的事情。
我在用户模型中的登录方法:
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);
});
});
});
从书架User
模型实现登录和调用User.login
的控制器动作:
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()
可以 return 拒绝承诺。在那种情况下,.catch(User.NotFoundError ...)
(catch #1) 行应该捕获它并且 return 一个 404。我还打算 login()
到 return 当 bcrypt
确定传递给 login()
的密码与用户的密码不匹配,在这种情况下 User.NotFoundError
catch 语句下面的 "catch-all" (捕获 #2)应该 return a 401.
如果我输入的密码不正确,上面代码中的 logUserIn()
控制器操作会使用错误消息 { error: "Cannot set property 'message' of undefined" }
而不是消息 'Password didn't match!'
来捕获 #2我在 login()
中拒绝了。如果我输入一个不存在的电子邮件,则永远不会发送响应,并且会在控制台中抛出错误 Unhandled rejection CustomError: EmptyResponse
。只有有效的输入才有效。
尝试修复: 直接在模型中捕获 User.NotFoundError
。
我将第一个问题移到了用户模型中,这样登录方法现在看起来像:
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);
});
})
.catch(User.NotFoundError, () => reject({ error: 'User not found!' }));
});
通过这种方式,我可以正确捕获这两个错误(密码不正确和电子邮件不存在),但是这样我无法在控制器中指定状态代码。如果找不到具有给定电子邮件的用户,那么它应该 return 一个 404,但是如果密码不正确,那么它应该 return 一个 401,但是这两个错误都会出现 -控制器操作中的所有(捕获#2)(始终 returns a 401)。
为了解决这个问题,在 User
模型中我可以做 .catch(User.NotFoundError, () => reject({ name: 'NotFoundError', message: 'User not found!' }))
并且在控制器操作中我可以检查 const statusCode = err.name === 'NotFoundError' ? 404 : 401
我遇到了什么样的错误但是这看起来真的很乱,并且错过了这些 .catch
语句的要点。
有没有办法从模型的登录方法中捕获 User.NotFoundError
以及 logInUser
中的任何其他错误?为什么我一开始的设置不起作用,usersAuthController.js 中有两个 catch
语句,Cannot set property 'message' of undefined'
和 CustomError: EmptyResponse
错误意味着什么(它有与混淆 Bookshelf 的 Bluebird 承诺与内置 ES6 承诺有关)?处理此问题的最佳方法是什么?
在您的初始实施中,您没有传播任何可能由 User.fetch()
引起的拒绝。此外,因为 User.fetch()
已经 returns 一个承诺,用一个新的承诺包装它有点反模式(尽管你仍然需要用一个承诺包装 bcrypt.compare()
,因为那只是与回调一起工作)。
试试这个:
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);
});
})
});
}