将NestJS集成到Angular Universal后,在日志中又发现了404重定向错误:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at new NodeError (node:internal/errors:387:5) at ServerResponse.setHeader (node:_http_outgoing:644:11) at ServerResponse.header (/.../dist/server/main.js:1:540819) at ServerResponse.send (/.../dist/server/main.js:1:534958) at ServerResponse.json (/.../dist/server/main.js:1:536362) at /.../dist/server/main.js:1:6326118 at Generator.next (<anonymous>) at asyncGeneratorStep (/.../dist/server/main.js:1:5440384) at _next (/.../dist/server/main.js:1:5440687) at _ZoneDelegate2.invoke (/.../dist/server/main.js:1:3555128) { code: 'ERR_HTTP_HEADERS_SENT' }
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at new NodeError (node:internal/errors:387:5) at ServerResponse.setHeader (node:_http_outgoing:644:11) at ServerResponse.header (/.../dist/server/main.js:1:540819) at ServerResponse.send (/.../dist/server/main.js:1:534958) at ServerResponse.json (/.../dist/server/main.js:1:536362) at /.../dist/server/main.js:1:6326118 at Generator.next () at asyncGeneratorStep (/.../dist/server/main.js:1:5440384) at _next (/.../dist/server/main.js:1:5440687) at _ZoneDelegate2.invoke (/.../dist/server/main.js:1:3555128) { code: 'ERR_HTTP_HEADERS_SENT' }

虽然代码经过了压缩和混淆,但通过查看报错的代码依然可以发现蛛丝马迹,原来问题出在this.response.redirect('/404')调用之后。然而找到了报错的地方,却依然毫无头绪。对于Node.js服务端应用,这是再正常不过的重定向调用,怎么会报ERR_HTTP_HEADERS_SENT错误呢?

无奈,只能硬着头皮在压缩混淆后的代码中debug,尝试着找到问题出现的链路。

终于,理清了Angular Universal和NestJS混合应用的路由逻辑:

404重定向问题

如上图,其中7和8顺序不定,即8有可能在7前面先执行,而报错出现在第9步中(即:6、7中间,或8、7中间)。

如此,也就很好理解问题出现的原因了:在redirect后,Angular已经先行返回页面到客户端了,但此时,NestJS又执行了一遍路由,并因异常被filter拦截。

由此,解决思路,直觉上是在Angular渲染后block后续的路由,但无论是手动调用end(),还是在NestJS层再加一层Not Found handler,都无济于事。

后来,联想到集成NestJS之前也曾出现过类似问题,那时的解决方案是在express层的中间件中添加一段异常处理代码: