Javascript 向承诺添加catch块将返回挂起而不是拒绝
我有一个正在工作的apollo graphql express服务器。唯一的问题是express抱怨我在用于验证jwt令牌的承诺上没有catch块: (节点:96074)未处理的PromisejectionWarning:未处理的承诺拒绝。此错误源于在没有catch块的情况下抛出异步函数内部,或者拒绝未使用.catch()处理的承诺 我可以向promise添加catch块,但是当令牌无效时,它会返回Javascript 向承诺添加catch块将返回挂起而不是拒绝,javascript,node.js,error-handling,promise,graphql,Javascript,Node.js,Error Handling,Promise,Graphql,我有一个正在工作的apollo graphql express服务器。唯一的问题是express抱怨我在用于验证jwt令牌的承诺上没有catch块: (节点:96074)未处理的PromisejectionWarning:未处理的承诺拒绝。此错误源于在没有catch块的情况下抛出异步函数内部,或者拒绝未使用.catch()处理的承诺 我可以向promise添加catch块,但是当令牌无效时,它会返回pending,而不是rejected。这会导致身份验证流中断,因为我的graphql解析器依赖该
pending
,而不是rejected
。这会导致身份验证流中断,因为我的graphql解析器依赖该拒绝来阻止对db的访问
Fwiw这是我为auth使用的auth0建议设置它的方式。他们只是没有提到未处理的PromisejectionWarning
代码如下所示:
//server def
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
if (req.headers.authorization) {
const token = req.headers.authorization.split(' ')[1];
//THE PROMISE IN QUESTION
const authUserObj = new Promise((resolve, reject) => {
jwt.verify(token, getKey, options, (err, decoded) => {
if (err) {
reject(err);
}
if (decoded) {
resolve(decoded);
}
});
});
return {
authUserObj
};
}
},
introspection: true,
playground: true
});
//a graphql resolver that gets the rejection via authUserObj and catches the error
addUser: async (parent, args, {authUserObj}) => {
try {
const AuthUser = await authUserObj;
const response = await User.create(args);
return response;
} catch(err) {
throw new AuthenticationError('You must be logged in to do this');
}
}
这一切都有效。。。除了那个烦人的节点错误,我希望能战胜它!因此,我在promise中添加了一个catch块:
const authUserObj = new Promise((resolve, reject) => {
jwt.verify(token, getKey, options, (err, decoded) => {
if (err) {
console.log("-------rejected-------", err.message)
reject(err);
}
if (decoded) {
console.log("-------decoded-------")
resolve(decoded);
}
});
}).catch( err => { return err.message});
现在,authUserObj不再返回拒绝,而是挂起,任何人都可以添加用户,这与auth的目的背道而驰
如果有人知道如何在拒绝错误的同时抓住错误,我会洗耳恭听。谢谢。就像使用
try/catch
一样,如果您只是从.catch()
处理程序返回一个正常值(或不返回任何内容),则.catch()
会将承诺链从拒绝更改为已解决。当您返回“正常”值时,拒绝将被视为“已处理”,承诺链将使用该新值得到解决。这就是处理错误和继续正常处理的方式
要保持承诺链被拒绝,您必须抛出或返回被拒绝的承诺。这将保持承诺链被拒绝
因此,如果希望authUserObj
遵守拒绝的承诺,请更改此选项:
}).catch( err => { return err.message});
为此:
}).catch( err => { return Promise.reject(err.message)});
或者类似的抛出错误或返回被拒绝的承诺。问题不在于未处理的承诺被拒绝,而在于一般未处理的承诺。您尝试将承诺放入
上下文
对象中,然后仅在addUser
解析程序中等待承诺。在其他解析器中,可能根本不使用承诺,当jwt验证失败时,拒绝将不被处理。(此外,如果解析程序是异步执行的,则在它们能够处理承诺之前,承诺可能会被拒绝)
相反,应该异步执行,返回一个包含用户详细信息的上下文对象承诺。这意味着在开始执行查询之前,请求将失败:
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
if (req.headers.authorization) {
const token = req.headers.authorization.split(' ')[1];
return new Promise((resolve, reject) => {
jwt.verify(token, getKey, options, (err, decoded) => {
if (err) reject(err);
else resolve(decoded);
});
}).then(authUser => {
if (authUser) return { authUser };
// else return {};
});
// .catch(err => { … }) - you may chose to ignore verification failure,
// and still return a context object (without an `authUser`)
}
// else return {}; - when not sending the header, no token will be checked at all
},
introspection: true,
playground: true
});
谢谢你,这很清楚,很有效。非常感谢。这不是阿波罗服务器的正确解决方案。我会写一个简短的答案,现在我又在读了一遍,我不确定重述错误有助于避免未经处理的拒绝……因此,在我看来,这根本不是一个解决方案。@j1mmy-这是对你问题标题的解释。为了提醒你们,这个标题是给承诺添加一个catch块,返回挂起而不是拒绝,非常好,谢谢。我可能会那样做。@j1mm如果是那样的话,你可能会想接受我的答案。很高兴能帮上忙!
// a graphql resolver that checks for the authUserObj
addUser: async (parent, args, {authUserObj}) => {
if (!authUserObj) { // you might also want to check specific claims of the jwt
throw new AuthenticationError('You must be logged in to do this');
}
const response = await User.create(args);
return response;
}