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

Angular HTTP拦截器未转发reportProgress事件至组件的问题

解决Angular拦截器无法转发上传进度事件的问题

我一眼就发现问题出在你的LoaderInterceptor里——你现在只把HttpResponse类型的事件转发给了组件的观察者,而上传进度相关的HttpProgressEvent(比如上传开始、进度更新这类事件)全被拦截器“吞”掉了,所以组件那边自然收不到进度信息。

问题根源

在你的拦截器代码中,只有当event instanceof HttpResponse时才调用observer.next(event),但上传过程中的进度事件属于其他HttpEvent子类,根本没被转发出去。你在拦截器里能看到console.log(event)输出进度事件,但组件的订阅接不到,就是因为这一步的遗漏。

修复拦截器代码

修改LoaderInterceptor的subscribe回调,把所有事件都转发给观察者,然后在合适的时机(收到响应、错误、完成时)处理请求队列的清理:

import {Injectable} from '@angular/core'; 
import { HttpResponse, HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpEventType } from '@angular/common/http'; 
import {Observable} from 'rxjs'; 
import {StateService} from '../services/state.service'; 

@Injectable() 
export class LoaderInterceptor implements HttpInterceptor { 
  private requests: HttpRequest<any>[] = []; 

  constructor(private alertService: AlertService, private stateService: StateService) { } 

  removeRequest(req: HttpRequest<any>) { 
    const i = this.requests.indexOf(req); 
    if (i >= 0) { 
      this.requests.splice(i, 1); 
    } 
    this.stateService.isLoading$.next(this.requests.length > 0); 
  } 

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 
    this.requests.push(req); 
    this.stateService.isLoading$.next(true); 

    return new Observable(observer => { 
      const subscription = next.handle(req) 
        .subscribe( 
          event => { 
            console.log(event); 
            // 转发所有事件,包括进度事件!
            observer.next(event);
            // 只有当是响应事件时才清理请求
            if (event instanceof HttpResponse) { 
              this.removeRequest(req); 
            } 
          }, 
          err => { 
            this.alertService.setAlert('error', err.message); 
            this.removeRequest(req); 
            observer.error(err); 
          }, 
          () => { 
            this.removeRequest(req); 
            observer.complete(); 
          }); 

      return () => { 
        this.removeRequest(req); 
        subscription.unsubscribe(); 
      }; 
    }); 
  } 
}

为什么这样改?

  • 移除了对HttpResponse的判断,直接把所有HttpEvent(包括进度事件、响应事件等)都通过observer.next(event)转发给组件的订阅。
  • 只在收到HttpResponse、错误或者流完成时清理请求队列,保证加载状态的逻辑不受影响。

组件端优化(可选)

你的upload.component.ts基础配置已经没问题了,要是想更清晰地处理进度,可以在订阅时判断事件类型:

this.http.request(req)
  .pipe(
    tap(event => {
      if (event.type === HttpEventType.UploadProgress) {
        // 计算上传进度百分比
        const progress = Math.round(100 * event.loaded / (event.total || 1));
        console.log(`${file.name} 上传进度: ${progress}%`);
      } else if (event instanceof HttpResponse) {
        console.log(`${file.name} 上传完成`);
      }
    })
  )
  .subscribe();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 21:22:49