You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:24:28