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

Angular18升级后API回调参数偶现undefined问题成因咨询

问题:Angular升级后API响应偶现undefined的成因分析

问题背景

将Angular从16升级至18.2.13并切换构建模式为angular-devkit/build-angular:application后,调用后端API的QuickRenew函数中,receiveCallBack执行时偶现resHubDto为undefined,但后端明确返回了有效值。将responseData = res修改为responseData = {...res}后问题解决,需分析具体成因。

相关代码

QuickRenew函数

public QuickRenew = (requestData: myRequestHUb, receiveCallBack: (data: myREsHub) => void, receiveErrorCallBack: (data: myREsHub) => void, noSessionCallBack: (data: myREsHub) => void,
 completeCallBack: (data: myREsHub) => void = null,
 receiveUnExceptedErrorCallBack: (data: myREsHub ) => void,
 reciveSubMaintenanceModeCallBack:(data: myREsHub ) => void): void => {
   const url = location.protocol + "//" + location.host + '/api/QuickHub/Quickrenew';

     let responseData: myREsHub = null;
     this.http.post<any>(url, requestData, { responseType: "json", headers: { "X-XSRF-TOKEN" : checkToken } })
         .subscribe(
             (res: any) => {
                 responseData = res;

                 if (!!responseData.MaintenanceMode) {
                     location.href = "/";
                     return;
                 }

                 if (responseData.NoSession) {
                     noSessionCallBack(responseData);
                 } else if (responseData.IsUnexpectedError) {
                     receiveUnExceptedErrorCallBack(responseData);
                 } else if (responseData.IsError) {
                    
                     receiveErrorCallBack(responseData);
                 } else if (responseData.SubMaintenanceMode){
                     reciveSubMaintenanceModeCallBack(responseData);
                 }else {
                    
                     receiveCallBack(responseData);
                    
                 }
             },
             e => {
                 receiveUnExceptedErrorCallBack(responseData);
             },
             () => {
                 console.log("success")
                 if (!!completeCallBack) {
                     completeCallBack(responseData);
                 }
             }
         );
 }

receiveCallBack函数

async (resHubDto: myResponse) => {
            console.log("implement start")
             
             const transferData = {
                 invoiceId: resHubDto.InvoiceId,
                
             };
             this.serviceContainer.DataTransferService.setData(transferData, this.serviceContainer.DataTransferService.QuickDomainRenewDoneKey);

             this.router.navigate(['/sp/quick/renewal/done']);
 }

依赖版本

"dependencies": {
  "@angular/animations": "^18.2.13",
  "@angular/cdk": "^18.2.14",
  "@angular/common": "^18.2.13",
  "@angular/compiler": "^18.2.13",
  "@angular/core": "^18.2.13",
  "@angular/forms": "^18.2.13",
  "@angular/platform-browser": "^18.2.13",
  "@angular/platform-browser-dynamic": "^18.2.13",
  "@angular/router": "^18.2.13",
  "@ngrx/store": "^18.1.1",
  "@ngrx/store-devtools": "^18.1.1",
  "@types/credit-card-type": "^9.0.0",
  "@types/file-saver": "^2.0.7",
  "@types/pikaday": "^1.7.9",
  "card-validator": "^8.1.1",
  "chart.js": "^4.4.3",
  "core-js": "^3.36.1",
  "credit-card-type": "^10.0.0",
  "dompurify": "^3.2.4",
  "esbuild": "^0.25.2",
  "file-saver": "^2.0.5",
  "gulp-esbuild": "^0.14.0",
  "lodash": "^4.17.21",
  "marked": "^15.0.7",
  "ng2-charts": "^6.0.1",
  "path-to-regexp": "^8.2.0",
  "pikaday": "^1.8.2",
  "rxjs": "^6.6.7",
  "trim-newlines": "^5.0.0",
  "tslib": "^2.6.2",
  "zone.js": "~0.14.4"
},

成因分析

  1. Angular 18 HTTP客户端底层实现变更
    Angular 18默认使用fetch替代了传统的XMLHttpRequest作为HTTP客户端的底层实现,在application构建模式下这一变更的影响更显著。fetch序列化响应后返回的是Proxy代理对象,而非普通JS对象。当receiveCallBack是异步函数时,代理对象可能因内部引用机制被过早回收,导致访问属性时出现undefined。

  2. 浅拷贝的修复原理
    使用{...res}进行浅拷贝,会提取代理对象的所有可枚举属性,生成一个独立的普通JS对象。这个对象脱离了原代理的引用链,不会被提前回收,能稳定保留后端返回的数据,因此解决了undefined问题。

  3. 新构建模式的优化放大问题
    angular-devkit/build-angular:application是Angular 17+引入的新构建模式,默认启用了更多激进优化(如深度树摇、代理对象内存优化),使得原本在旧构建模式下不明显的代理对象引用问题暴露出来。而Angular 16使用的旧构建模式中,HTTP响应返回的是普通对象,因此无此问题。

  4. TypeScript版本的间接影响
    Angular 18配套的TypeScript 5.x版本对类型检查和对象处理更严格,代理对象与自定义类型myREsHub/myResponse的兼容性问题被放大,间接导致了偶现的undefined情况,但这并非直接成因。


内容的提问来源于stack exchange,提问作者công

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:35:54