MST

星途 面试题库

面试题:Angular HTTP请求错误处理与重试机制在复杂业务场景下的优化

在一个具有多个模块且业务复杂的Angular项目中,不同模块的HTTP请求有着不同的错误处理和重试需求。比如某些关键数据的请求,重试次数更多且需要在后台记录详细的重试日志;而一些非关键信息的请求,只需要简单提示用户。请设计一套通用的、可扩展的错误处理与重试机制架构,满足这些不同需求,并详细说明如何在各个模块中灵活应用该架构。
33.0万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

1. 设计架构

  1. 拦截器(Interceptor)设计
    • 创建一个基础的HTTP拦截器,用于捕获HTTP请求的错误。在Angular中,拦截器实现HttpInterceptor接口。
    • 示例代码:
    import { Injectable } from '@angular/core';
    import {
      HttpEvent,
      HttpHandler,
      HttpInterceptor,
      HttpRequest,
    } from '@angular/common/http';
    import { Observable, catchError, finalize } from 'rxjs';
    
    @Injectable()
    export class BaseHttpInterceptor implements HttpInterceptor {
      intercept(
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
          catchError((error) => {
            // 这里开始处理错误
            return this.handleError(error, request, next);
          }),
          finalize(() => {
            // 可在这里添加通用的结束逻辑,比如移除加载指示器
          })
        );
      }
    
      private handleError(
        error: any,
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        // 通用错误处理逻辑,可根据需求扩展
        return new Observable<HttpEvent<any>>();
      }
    }
    
  2. 错误处理与重试策略
    • 重试策略抽象类:创建一个抽象类定义重试策略的基本方法,如shouldRetry判断是否应该重试,retry执行重试逻辑。
    export abstract class RetryStrategy {
      abstract shouldRetry(error: any, attempt: number): boolean;
      abstract retry(request: HttpRequest<any>, next: HttpHandler, attempt: number): Observable<HttpEvent<any>>;
    }
    
    • 关键数据请求重试策略:继承重试策略抽象类,实现关键数据请求的重试逻辑,例如设置较多的重试次数,并记录重试日志。
    import { Injectable } from '@angular/core';
    import {
      HttpEvent,
      HttpHandler,
      HttpRequest,
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    
    @Injectable()
    export class CriticalDataRetryStrategy extends RetryStrategy {
      private maxRetries = 3;
      private logUrl = 'your - logging - api - url';
    
      shouldRetry(error: any, attempt: number): boolean {
        return attempt < this.maxRetries;
      }
    
      retry(request: HttpRequest<any>, next: HttpHandler, attempt: number): Observable<HttpEvent<any>> {
        // 记录重试日志到后台
        const logRequest = request.clone({
          url: this.logUrl,
          body: {
            error,
            attempt,
            originalUrl: request.url
          }
        });
        // 发送日志请求
        // 实际应用中可使用Angular HttpClient发送请求
        // 这里简单返回一个空的Observable示意
        return new Observable<HttpEvent<any>>();
        // 执行重试
        return next.handle(request);
      }
    }
    
    • 非关键信息请求重试策略:同样继承重试策略抽象类,实现简单的重试逻辑,如只重试一次并简单提示用户。
    import { Injectable } from '@angular/core';
    import {
      HttpEvent,
      HttpHandler,
      HttpRequest,
    } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { MatSnackBar } from '@angular/material/snack - bar';
    
    @Injectable()
    export class NonCriticalDataRetryStrategy extends RetryStrategy {
      private maxRetries = 1;
    
      constructor(private snackBar: MatSnackBar) {
        super();
      }
    
      shouldRetry(error: any, attempt: number): boolean {
        return attempt < this.maxRetries;
      }
    
      retry(request: HttpRequest<any>, next: HttpHandler, attempt: number): Observable<HttpEvent<any>> {
        if (attempt === this.maxRetries - 1) {
          this.snackBar.open('请求出现问题,请稍后重试', '关闭', {
            duration: 3000
          });
        }
        return next.handle(request);
      }
    }
    
  3. 策略管理与选择
    • 创建一个策略管理器,根据请求的类型或其他条件选择合适的重试策略。可以通过在请求的headersurl中添加标识来判断。
    import { Injectable } from '@angular/core';
    import { CriticalDataRetryStrategy, NonCriticalDataRetryStrategy, RetryStrategy } from './retry - strategies';
    
    @Injectable()
    export class RetryStrategyManager {
      constructor(
        private criticalDataRetryStrategy: CriticalDataRetryStrategy,
        private nonCriticalDataRetryStrategy: NonCriticalDataRetryStrategy
      ) {}
    
      getRetryStrategy(request: HttpRequest<any>): RetryStrategy {
        // 假设请求头中有 'critical - data' 标识为关键数据请求
        if (request.headers.has('critical - data')) {
          return this.criticalDataRetryStrategy;
        }
        return this.nonCriticalDataRetryStrategy;
      }
    }
    
  4. 错误处理的通用化
    • 在基础拦截器的handleError方法中,调用策略管理器获取对应的重试策略,并执行重试逻辑。
    import { Injectable } from '@angular/core';
    import {
      HttpEvent,
      HttpHandler,
      HttpInterceptor,
      HttpRequest,
    } from '@angular/common/http';
    import { Observable, catchError, finalize } from 'rxjs';
    import { RetryStrategyManager } from './retry - strategy - manager';
    
    @Injectable()
    export class BaseHttpInterceptor implements HttpInterceptor {
      constructor(private retryStrategyManager: RetryStrategyManager) {}
    
      intercept(
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
          catchError((error) => {
            return this.handleError(error, request, next);
          }),
          finalize(() => {
            // 可在这里添加通用的结束逻辑,比如移除加载指示器
          })
        );
      }
    
      private handleError(
        error: any,
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        const retryStrategy = this.retryStrategyManager.getRetryStrategy(request);
        let attempt = 0;
        const retryLogic = () => {
          if (retryStrategy.shouldRetry(error, attempt)) {
            attempt++;
            return retryStrategy.retry(request, next, attempt).pipe(
              catchError((newError) => {
                return retryLogic();
              })
            );
          }
          // 这里可以添加最终的错误处理,如显示通用错误提示给用户
          return new Observable<HttpEvent<any>>();
        };
        return retryLogic();
      }
    }
    

2. 在各个模块中灵活应用

  1. 模块引入拦截器:在每个需要应用错误处理和重试机制的模块的NgModule中,将基础HTTP拦截器添加到providers数组中。
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform - browser';
    import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
    import { BaseHttpInterceptor } from './base - http - interceptor';
    import { RetryStrategyManager } from './retry - strategy - manager';
    import { CriticalDataRetryStrategy } from './critical - data - retry - strategy';
    import { NonCriticalDataRetryStrategy } from './non - critical - data - retry - strategy';
    
    @NgModule({
      imports: [BrowserModule, HttpClientModule],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: BaseHttpInterceptor,
          multi: true
        },
        RetryStrategyManager,
        CriticalDataRetryStrategy,
        NonCriticalDataRetryStrategy
      ]
    })
    export class YourModule {}
    
  2. 设置请求标识:在各个模块的服务中发送HTTP请求时,根据需求设置请求头标识,以确定使用哪种重试策略。
    import { Injectable } from '@angular/core';
    import { HttpClient, HttpRequest } from '@angular/common/http';
    
    @Injectable()
    export class YourService {
      constructor(private http: HttpClient) {}
    
      getCriticalData() {
        const request = new HttpRequest('GET', 'your - critical - data - url', {
          headers: {
            'critical - data': 'true'
          }
        });
        return this.http.request(request);
      }
    
      getNonCriticalData() {
        return this.http.get('your - non - critical - data - url');
      }
    }
    

通过以上架构设计,可以实现一个通用且可扩展的错误处理与重试机制,满足不同模块HTTP请求的不同错误处理和重试需求。