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

Angular5带进度追踪的Http请求引发路由异常问题

问题分析与解决方案

看起来你的路由异常问题大概率是手动调用detectChanges()干扰了Angular的变更检测周期,再加上上传代码里的异步逻辑瑕疵共同导致的,我来一步步帮你解决:

核心问题:手动变更检测打破了Angular的默认机制

Angular的HTTP请求(包括进度事件)本身是运行在NgZone中的,默认会自动触发变更检测,你不需要手动调用this.ref.detectChanges()。频繁或不恰当的手动检测会导致组件的变更检测状态紊乱,比如让组件脱离了Angular的自动检测周期——这就解释了为什么路由跳转后视图不更新、两个组件同时显示,而点击外部的搜索栏(触发了一次全局变更检测)后又恢复正常。

具体修复步骤

1. 移除所有手动detectChanges()调用

把上传函数里的两处this.ref.detectChanges()全部删掉,Angular会自动处理HTTP事件带来的视图更新。如果确实遇到某些特殊场景需要手动触发(比如非NgZone内的异步操作),也应该用this.ref.markForCheck()替代,它只会标记组件需要在下一个检测周期被检查,不会直接触发检测,更安全。

2. 管理HTTP订阅,避免内存泄漏与组件残留

你的上传请求订阅如果没有在组件销毁时取消,会导致组件实例无法被正确回收,这也是路由跳转后旧组件依然显示的可能原因之一:

  • 在组件类中定义一个订阅对象:
private uploadSubscription?: Subscription;
  • 在订阅HTTP请求时赋值:
this.uploadSubscription = this.http.request(req).subscribe(...);
  • 添加组件销毁钩子,取消订阅:
ngOnDestroy() {
  this.uploadSubscription?.unsubscribe();
}

3. 修正上传代码的异步逻辑瑕疵

你当前的代码在循环里创建HttpRequest,然后在fileEntry.file()的异步回调里添加文件到FormData——这里存在逻辑问题:循环会先执行完,而回调是异步的,导致最后发送请求时可能前面的文件还没被添加到FormData里(虽然你说上传功能正常,但这是浏览器FormData的引用特性带来的巧合,逻辑上不严谨)。

改用Promise.all等待所有文件都添加完成后再发送请求:

upload(){ 
  this.showFilesToUpload = false; 
  this.showProgressBar = true; 
  const headers = new HttpHeaders().set('x-access-token', localStorage.getItem('x-access-token')); 
  const formData = new FormData(); 

  // 收集所有文件读取的Promise
  const filePromises = this.files.map(fileItem => {
    return new Promise<void>((resolve) => {
      fileItem.fileEntry.file(file => {
        formData.append("fileupload", file, fileItem.relativePath);
        resolve();
      });
    });
  });

  // 等待所有文件添加完毕后再发送请求
  Promise.all(filePromises).then(() => {
    const req = new HttpRequest('POST', this.domain + 'api/uploadpdf', formData, { 
      reportProgress: true, 
      headers: headers 
    }); 

    this.uploadSubscription = this.http.request(req).subscribe(event => { 
      if (event.type === HttpEventType.UploadProgress) { 
        this.setProzentUploaded(Math.round(100 * event.loaded / event.total)); 
        // 这里不再需要detectChanges()
      } else if (event instanceof HttpResponse) { 
        console.log(event); 
        swal({ title: 'All Documents Uploaded!', type: 'success' }).then((isConfirm) => { 
          if (isConfirm) { 
            this.showProgressBar = false; 
            this.showFilesToUpload = true; 
            this.files = []; 
            this.progressBarValue = 0; 
            // 这里也不需要detectChanges()
          } 
        }); 
      } 
    }, error => {
      // 别忘了处理上传错误,避免组件一直停留在加载状态
      console.error('Upload failed:', error);
      this.showProgressBar = false;
      this.showFilesToUpload = true;
    }); 
  });
}

验证与额外建议

做完以上修改后,重新测试上传后的路由跳转:

  • 路由应该能正常切换,视图只会显示目标组件
  • 路由按钮的功能也会恢复正常

如果问题依然存在,可以检查:

  • 组件是否有手动调用this.ref.detach()的代码,如果有,需要在合适的时机调用this.ref.reattach()
  • 确保你的路由配置没有错误,比如没有重复的路由路径

内容的提问来源于stack exchange,提问作者Daniel Klotzsche

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:42:09