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

NestJS路由处理器返回空JSON而非预期响应问题排查

NestJS /signout接口返回空对象问题排查

问题根因

  • 你使用的session中间件(默认是express-session)对session的修改、销毁操作都是异步执行的。代码中同步执行session.userId = null后,没有等待session状态持久化完成就直接返回响应,此时session的异步写入逻辑和NestJS的响应发送流程产生竞态,会覆盖已经构造好的响应体,最终返回空JSON{}。这也是为什么你在console.log中能看到res变量值符合预期,但接口返回异常——console.log是同步执行的,打印时res值确实正确,但后续异步的session操作打乱了响应发送流程。
  • 代码存在逻辑漏洞:返回语句被包裹在if (!session.userId)条件块内,如果出现session初始化异常、userId赋值失败等边界场景,函数不会命中if分支,没有显式返回值,默认返回undefined,经NestJS序列化后同样会得到空对象。
  • 代码中用JSON.parse(JSON.stringify())做深拷贝生成响应对象的写法完全冗余,既不会解决问题,还会增加不必要的性能开销。

修复方案

  1. 将路由处理函数改为异步形式,等待session操作执行完成后再返回响应。登出场景推荐直接销毁session,而非仅把userId置空,参考代码如下:
@Get('/signout')
async signOut(@Session() session: any) {
  // 等待session销毁完成,消除异步竞态
  await new Promise<void>((resolve, reject) => {
    session.destroy((err: Error | null) => {
      if (err) {
        reject(err);
        return;
      }
      resolve();
    });
  });
  // 直接返回响应对象即可,无需多余的深拷贝操作
  return { status: 'success' };
}
  1. 如果业务不需要销毁整个session,仅需要清空userId字段,就等待session.save()执行完成再返回:
@Get('/signout')
async signOut(@Session() session: any) {
  session.userId = null;
  // 等待session修改写入存储
  await new Promise<void>((resolve, reject) => {
    session.save((err: Error | null) => {
      if (err) {
        reject(err);
        return;
      }
      resolve();
    });
  });
  return { status: 'success' };
}
  1. 调整返回逻辑位置,不要把返回语句完全放在条件判断块内,确保所有代码分支都有明确的返回值,避免隐式返回undefined。

内容的提问来源于stack exchange,提问作者GURSIDAK SINGH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:27:21