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())做深拷贝生成响应对象的写法完全冗余,既不会解决问题,还会增加不必要的性能开销。
修复方案
- 将路由处理函数改为异步形式,等待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' }; }
- 如果业务不需要销毁整个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' }; }
- 调整返回逻辑位置,不要把返回语句完全放在条件判断块内,确保所有代码分支都有明确的返回值,避免隐式返回
undefined。
内容的提问来源于stack exchange,提问作者GURSIDAK SINGH
相关产品推荐
相关产品推荐

