Angular Universal项目服务端运行一段时间后自动崩溃如何解决
问题原因
该报错核心是服务端执行JSON.stringify()时遇到了带有循环引用的对象,触发未捕获异常,符合Node.js进程终止策略后直接导致服务崩溃,需要重启恢复。
具体到你提供的日志:
HTTP请求https://www.systemapi.ipdemy.ir/api/global/Bootstrapper调用失败后返回的HttpErrorResponse中,error字段是ProgressEvent对象,该对象的target/currentTarget都指向XMLHttpRequest实例,而XMLHttpRequest.upload指向XMLHttpRequestUpload实例,后者又存在_request属性指回原XMLHttpRequest实例,形成了循环引用链。
Angular Universal服务端渲染场景下,以下两种操作会触发JSON.stringify()调用进而抛出该错误:
- 你将完整的
HttpErrorResponse对象存入了TransferState(服务端向客户端传数据的媒介),Angular会自动序列化该对象传输给前端 - 你的全局日志/错误捕获逻辑中直接对完整错误对象做JSON序列化输出
同时Node.js默认对未处理的Promise rejection会抛出异常终止进程,这就是站点运行一段时间后自动崩溃的根因。
解决方案
1. 过滤HTTP错误对象的循环引用字段
所有服务端发起的HTTP请求,捕获错误时不要直接传递、存储完整的HttpErrorResponse,仅提取你需要的纯JSON字段,过滤掉XHR、ProgressEvent相关内容,示例代码:
import { catchError, throwError } from 'rxjs'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; // 你的HTTP请求逻辑 this.http.get('https://www.systemapi.ipdemy.ir/api/global/Bootstrapper') .pipe( catchError((err: HttpErrorResponse) => { // 仅保留无循环引用的必要字段 const formattedError = { status: err.status, statusText: err.statusText, message: err.message, url: err.url }; return throwError(() => formattedError); }) ) .subscribe();
2. 规范TransferState的使用
如果使用了TransferState传递数据,确保存入的所有对象都没有循环引用,禁止直接存入完整的请求响应/错误对象。
3. 添加全局异常捕获避免进程崩溃
在服务端入口文件server.ts中添加全局未处理Promise拒绝监听,避免异常直接终止进程:
process.on('unhandledRejection', (reason: any) => { // 仅打印安全字段,不要直接序列化整个reason console.error('未捕获的异步错误:', reason?.message || reason?.toString() || '未知错误'); });
如果需要对错误对象做序列化打日志,可以使用json-stringify-safe这类支持循环引用的序列化库替代原生JSON.stringify。
4. 修复Buffer Deprecation警告(可选)
排查项目中使用旧Buffer()构造函数的代码,替换为官方推荐的Buffer.from()、Buffer.alloc()、Buffer.allocUnsafe()方法;如果是第三方依赖触发的警告,升级对应依赖到最新版本即可。
内容的提问来源于stack exchange,提问作者h.zare

