将NestJS集成到Angular Universal后,在日志中又发现了404重定向错误:
- 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'
}
虽然代码经过了压缩和混淆,但通过查看报错的代码依然可以发现蛛丝马迹,原来问题出在this.response.redirect('/404')
调用之后。然而找到了报错的地方,却依然毫无头绪。对于Node.js服务端应用,这是再正常不过的重定向调用,怎么会报ERR_HTTP_HEADERS_SENT
错误呢?
无奈,只能硬着头皮在压缩混淆后的代码中debug,尝试着找到问题出现的链路。
终于,理清了Angular Universal和NestJS混合应用的路由逻辑:
如上图,其中7和8顺序不定,即8有可能在7前面先执行,而报错出现在第9步中(即:6、7中间,或8、7中间)。
如此,也就很好理解问题出现的原因了:在redirect
后,Angular已经先行返回页面到客户端了,但此时,NestJS又执行了一遍路由,并因异常被filter
拦截。
由此,解决思路,直觉上是在Angular渲染后block后续的路由,但无论是手动调用end()
,还是在NestJS层再加一层Not Found handler
,都无济于事。
后来,联想到集成NestJS之前也曾出现过类似问题,那时的解决方案是在express层的中间件中添加一段异常处理代码: