Javascript 使用ES6承诺和书架FJ捕捉错误
我在ExpressJS应用程序中向Bookshelf用户模型添加了一个非常基本的登录方法,但是我无法捕捉到用户模型中的登录函数返回的拒绝承诺中的错误。我正在查看Bookshelf在的文档中的示例登录,但该示例使用Bluebird,而我正在尝试对内置ES6承诺执行相同的操作 用户模型中的我的登录方法: userModel.js 实现登录并从书架Javascript 使用ES6承诺和书架FJ捕捉错误,javascript,node.js,express,es6-promise,bookshelf.js,Javascript,Node.js,Express,Es6 Promise,Bookshelf.js,我在ExpressJS应用程序中向Bookshelf用户模型添加了一个非常基本的登录方法,但是我无法捕捉到用户模型中的登录函数返回的拒绝承诺中的错误。我正在查看Bookshelf在的文档中的示例登录,但该示例使用Bluebird,而我正在尝试对内置ES6承诺执行相同的操作 用户模型中的我的登录方法: userModel.js 实现登录并从书架User模型调用User.login的控制器操作: usersAuthController.js 我的意图是,当Bookshelf的方法无法找到具有给定电子
User
模型调用User.login
的控制器操作:
usersAuthController.js
我的意图是,当Bookshelf的方法无法找到具有给定电子邮件的用户时,login()
可以返回一个被拒绝的承诺。在这种情况下,.catch(User.NotFoundError…
(catch#1)行应该捕获它并返回404。当bcrypt
确定传递给login()
的密码与用户密码不匹配时,我还打算login()
返回被拒绝的承诺,在这种情况下用户下方的“catch all”(catch#2)。NotFoundError
catch语句应返回401
如果我输入了不正确的密码,上述代码中的logUserIn()
控制器操作将捕获#2,错误消息为{error:“无法设置未定义的属性'message'}
,而不是消息'password not match!'代码>我在login()
中拒绝的消息。如果我输入了一封不存在的电子邮件,则永远不会发送响应,并且控制台中会抛出错误未处理的拒绝CustomError:EmptyResponse
。只有有效的输入才有效
尝试修复:而是直接在模型中捕获用户.NotFoundError
我将catch#1移动到用户模型中,以便登录方法现在看起来像:
userModel.js
通过这种方式,我可以正确捕获两个错误(不正确的密码和不存在的电子邮件),但通过这种方式,我无法在控制器中指定状态代码。如果找不到具有给定电子邮件的用户,则应返回404,但如果密码不正确,则应返回401,但这两个错误都会转到控制器操作(始终返回401)中的catch all(catch#2)
为了解决这个问题,在User
模型中,我可以执行.catch(User.NotFoundError,()=>reject({name:'NotFoundError',message:'User not found!'}))
并且在控制器操作中,我可以检查const statusCode=err.name=='NotFoundError'得到的错误类型?404:401
但这看起来真的很混乱,没有抓住这些.catch
语句的要点
是否有方法从模型的登录方法中捕获用户.NotFoundError
,以及登录用户
中的所有其他错误?为什么我最初的设置不起作用,在usersAuthController.js中既有catch
语句,又有无法设置未定义的属性“message”和CustomError:EmptyResponse
错误意味着什么(这是否与Bookshelf的Bluebird承诺与内置ES6承诺的混淆有关)?处理这一问题的最佳方法是什么?在最初的实现中,您不会传播任何可能由User.fetch()
引起的拒绝。另外,因为User.fetch()
已经返回了一个承诺,用新承诺包装它有点反模式(尽管您仍然需要用承诺包装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);
});
})
});
}
在最初的实现中,您不会传播任何可能由User.fetch()
引起的拒绝。另外,因为User.fetch()
已经返回了一个承诺,用新的承诺包装它有点反模式(尽管您仍然需要包装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);
});
})
});
}
谢谢!我只是想澄清一下,通常我应该在什么时候把东西包装在承诺中(如果我得到了这一点,就是在中返回承诺的意义。然后是为了我可以链接。然后s)?@satray如果某个东西已经返回了一个承诺,你就不必包装它。在这种情况下,因为bcrypt.compare
不返回承诺,它会被包装(但“尽可能晚”)。即使你处理.then()
和.catch(),返回承诺(和承诺链)总是一件好事
已经有了。谢谢!我只是想澄清一下,通常我应该在什么时候把东西包装在承诺中(如果我得到了这个,就是在中返回承诺的目的。
就是为了让我可以链接。然后
s)?@satray如果某个东西已经返回了一个承诺,你就不必包装它。在这种情况下,因为bcrypt.compare
不返回承诺,它会被包装(但“尽可能晚”)。即使你处理.then()
和.catch(),返回承诺(和承诺链)总是一件好事
已经。避免!您应该只在login
函数中提示bcrypt.compare
。避免!您应该只在login
函数中提示bcrypt.compare
。
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!' }));
});
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);
});
})
});
}