Node.js中如何从回调函数捕获错误并返回JSON响应?
问题解决与优化方案
原代码的核心问题
- 异步逻辑顺序错误:
revokeToken里在数据库操作完成前就调用了callback("Token Deleted!"),导致数据库操作的结果无法正确传递。 - 接口响应时机错误:
res.json在revokeToken的异步回调执行前就发送了,此时errmsg还没被赋值,无法返回真实的错误或结果。 revokeToken内部错误处理混乱:不管删除成功与否都返回err,没有正确区分删除失败(比如没找到token)和数据库异常。
优化后的实现(使用Async/Await)
这种写法更直观,异步逻辑清晰,错误处理更完善:
// 先将revokeToken改造成返回Promise的函数 const revokeToken = async (tokenObj) => { const result = await tokenModel.deleteOne({ accessToken: tokenObj.accessToken }); // 判断是否成功删除了记录 if (result.deletedCount !== 1) { throw new Error("未找到对应的Token,删除失败"); } return "Token Deleted!"; }; // 改造后的logout接口 app.post('/api/logout', async (req, res) => { try { // 先校验Authorization头是否存在 if (!req.headers.authorization) { return res.status(400).json({ data: null, result: { isError: true, status: 400, errorMsg: "缺少Authorization请求头" } }); } const tokenArray = req.headers.authorization.split(" "); // 校验token格式是否正确(Bearer xxxx) if (tokenArray.length !== 2 || tokenArray[0] !== 'Bearer') { return res.status(400).json({ data: null, result: { isError: true, status: 400, errorMsg: "Authorization格式错误,应为Bearer [token]" } }); } const token = tokenArray[1]; const tokenObj = { accessToken: token }; // 调用revokeToken并等待结果 const message = await revokeToken(tokenObj); // 成功响应 res.json({ data: null, result: { isError: false, status: 200, errorMsg: message } }); } catch (err) { // 捕获所有错误并返回 res.status(500).json({ data: null, result: { isError: true, status: 500, errorMsg: err.message } }); } });
关键优化点说明
- 改用Async/Await:替代回调函数,让异步代码像同步代码一样易读,避免回调地狱。
- 完善参数校验:提前检查请求头是否存在、格式是否正确,避免后续逻辑出错。
- 明确错误类型:区分Token不存在的业务错误和数据库异常,统一用
throw抛出,在接口层统一捕获处理。 - 正确的响应时机:等待异步操作完成后再发送响应,确保返回的数据是最新的。
如果坚持使用回调函数(不推荐)
如果一定要用回调写法,需要修正回调的调用时机和错误传递:
const revokeToken = function(tokenObj, callback) { tokenModel.deleteOne({ accessToken: tokenObj.accessToken }).exec((err, results) => { // 先判断数据库是否出错 if (err) { return callback(err); } // 判断是否删除成功 if (results.deletedCount !== 1) { return callback(new Error("未找到对应的Token,删除失败")); } // 成功则传递成功消息 callback(null, "Token Deleted!"); }); }; app.post('/api/logout', (req, res) => { if (!req.headers.authorization) { return res.status(400).json({ data: null, result: { isError: true, status: 400, errorMsg: "缺少Authorization请求头" } }); } const tokenArray = req.headers.authorization.split(" "); if (tokenArray.length !== 2 || tokenArray[0] !== 'Bearer') { return res.status(400).json({ data: null, result: { isError: true, status: 400, errorMsg: "Authorization格式错误,应为Bearer [token]" } }); } const token = tokenArray[1]; const tokenObj = { accessToken: token }; revokeToken(tokenObj, (err, message) => { if (err) { return res.status(500).json({ data: null, result: { isError: true, status: 500, errorMsg: err.message } }); } res.json({ data: null, result: { isError: false, status: 200, errorMsg: message } }); }); });
内容的提问来源于stack exchange,提问作者Manas S. Roy
相关产品推荐
相关产品推荐

