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

Angular 11/13:仅无显式错误处理时触发的4xx/5xx拦截器开发

解决方案:Angular 11/13 条件式错误处理HttpInterceptor

要实现仅当请求未显式指定错误处理函数时才展示错误提示的需求,核心思路是跟踪每个请求的订阅状态,在拦截器中判断是否需要触发全局错误提示。以下是具体实现步骤:


1. 定义上下文标记Token

创建一个InjectionToken,用来在请求上下文中存储该请求是否有自定义错误处理的标记:

import { InjectionToken } from '@angular/core';

export const HAS_ERROR_HANDLER = new InjectionToken<boolean>('HAS_ERROR_HANDLER');

2. 包装HttpClient,跟踪错误处理状态

创建自定义HttpService包装Angular原生HttpClient,在订阅时判断是否传入了错误处理回调,并将状态写入请求上下文:

import { Injectable } from '@angular/core';
import { HttpClient, HttpContext } from '@angular/common/http';
import { Observable } from 'rxjs';
import { HAS_ERROR_HANDLER } from './has-error-handler.token';

@Injectable({ providedIn: 'root' })
export class HttpService {
  constructor(private http: HttpClient) {}

  // 封装GET方法,同理可扩展POST/PUT/DELETE等
  get<T>(url: string, options?: { context?: HttpContext }): Observable<T> {
    const request$ = this.http.get<T>(url, options);
    return this.wrapObservable(request$, options?.context);
  }

  private wrapObservable<T>(source$: Observable<T>, context?: HttpContext): Observable<T> {
    return new Observable<T>((subscriber) => {
      const subscription = source$.subscribe({
        next: value => subscriber.next(value),
        error: err => {
          // 判断订阅者是否传入了错误处理函数
          const hasErrorHandler = typeof subscriber.error === 'function';
          // 将状态写入上下文(若存在)
          if (context) {
            context.set(HAS_ERROR_HANDLER, hasErrorHandler);
          }
          subscriber.error(err);
        },
        complete: () => subscriber.complete()
      });
      return subscription;
    });
  }
}

3. 实现HttpInterceptor

编写拦截器,拦截4xx/5xx错误,根据上下文标记决定是否展示全局错误提示:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpErrorResponse,
} from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { HAS_ERROR_HANDLER } from './has-error-handler.token';
// 替换成你项目中使用的错误提示组件(比如Material SnackBar、自定义弹窗等)
import { MatSnackBar } from '@angular/material/snack-bar';

@Injectable()
export class ErrorHandlingInterceptor implements HttpInterceptor {
  constructor(private snackBar: MatSnackBar) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler) {
    // 初始化上下文标记为false
    const context = request.context.set(HAS_ERROR_HANDLER, false);
    const modifiedRequest = request.clone({ context });

    return next.handle(modifiedRequest).pipe(
      catchError((error: HttpErrorResponse) => {
        // 仅处理4xx/5xx状态码错误
        if (error.status >= 400 && error.status < 600) {
          // 获取上下文标记
          const hasErrorHandler = modifiedRequest.context.get(HAS_ERROR_HANDLER);
          // 无自定义错误处理时,展示全局提示
          if (!hasErrorHandler) {
            this.snackBar.open(
              `请求失败: ${error.message || `状态码 ${error.status}`}`,
              '关闭',
              { duration: 5000, panelClass: ['error-toast'] }
            );
          }
        }
        return throwError(() => error);
      })
    );
  }
}

4. 注册拦截器

在AppModule中注册该拦截器:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ErrorHandlingInterceptor } from './error-handling.interceptor';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: ErrorHandlingInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

使用示例

场景1:自定义错误处理(拦截器不生效)

// 传入了error回调,拦截器不会展示全局提示
this.httpService.get('/api/data').subscribe(
  data => console.log('请求成功:', data),
  err => console.error('自定义错误处理:', err)
);

场景2:无自定义错误处理(拦截器自动展示提示)

// 未传入error回调,拦截器会弹出全局错误提示
this.httpService.get('/api/data').subscribe(
  data => console.log('请求成功:', data)
);

原理说明

  1. 通过HttpContext存储每个请求的错误处理状态,这是Angular 10+提供的安全传递请求元数据的方式,兼容11/13版本。
  2. 自定义HttpService包装原生请求,在订阅阶段判断是否传入了错误处理函数,并更新上下文标记。
  3. 拦截器在捕获到4xx/5xx错误时,读取上下文标记,决定是否触发全局错误提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 07:55:40