面试题答案
一键面试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>>(); } }
- 创建一个基础的HTTP拦截器,用于捕获HTTP请求的错误。在Angular中,拦截器实现
- 错误处理与重试策略:
- 重试策略抽象类:创建一个抽象类定义重试策略的基本方法,如
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); } }
- 重试策略抽象类:创建一个抽象类定义重试策略的基本方法,如
- 策略管理与选择:
- 创建一个策略管理器,根据请求的类型或其他条件选择合适的重试策略。可以通过在请求的
headers
或url
中添加标识来判断。
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; } }
- 创建一个策略管理器,根据请求的类型或其他条件选择合适的重试策略。可以通过在请求的
- 错误处理的通用化:
- 在基础拦截器的
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. 在各个模块中灵活应用
- 模块引入拦截器:在每个需要应用错误处理和重试机制的模块的
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 {}
- 设置请求标识:在各个模块的服务中发送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请求的不同错误处理和重试需求。