Angular 11+全局实现API超时重试按钮方案咨询
实现方案:全局HTTP超时手动重试机制
核心思路
通过Angular HTTP拦截器结合RxJS操作符,实现全局API请求30秒超时检测;用Subject作为事件总线连接用户重试操作与请求重发逻辑,完全由用户手动触发重试,避免自动重试。
具体实现步骤
1. 构建重试状态管理服务
创建全局服务存储待重试请求、管理重试触发事件:
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RetryService { private pendingRequest: HttpRequest<any> | null = null; private retryTrigger$ = new Subject<void>(); setPendingRequest(req: HttpRequest<any>) { this.pendingRequest = req; } getPendingRequest() { return this.pendingRequest; } triggerRetry() { this.retryTrigger$.next(); } getRetryStream() { return this.retryTrigger$.asObservable(); } }
2. 编写HTTP超时拦截器
在拦截器中处理超时逻辑,结合重试服务实现手动重发:
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import { Observable, defer, throwError, timeout } from 'rxjs'; import { catchError, switchMap, tap } from 'rxjs/operators'; import { RetryService } from './retry.service'; @Injectable() export class TimeoutRetryInterceptor implements HttpInterceptor { constructor(private retryService: RetryService) {} intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { return defer(() => { // 发起请求并设置30秒超时 return next.handle(request).pipe( timeout(30000), catchError((error: HttpErrorResponse) => { // 捕获超时错误,存储请求并抛出提示 if (error.name === 'TimeoutError') { this.retryService.setPendingRequest(request); return throwError(() => new Error('请求超时,请点击重试')); } // 其他错误直接抛出 return throwError(() => error); }) ); }).pipe( // 监听重试触发事件,重发原请求 switchMap(() => { return this.retryService.getRetryStream().pipe( switchMap(() => { const pendingReq = this.retryService.getPendingRequest(); if (pendingReq) { return next.handle(pendingReq); } return throwError(() => new Error('无待重试请求')); }), // 重试完成后清空待请求 tap(() => this.retryService.setPendingRequest(null)) ); }) ); } }
3. 全局重试按钮组件
创建全局组件监听超时错误,显示重试按钮并触发重试:
import { Component } from '@angular/core'; import { RetryService } from './retry.service'; import { ErrorHandler } from '@angular/core'; @Component({ selector: 'app-global-retry', template: ` <div *ngIf="showRetryBtn" class="retry-modal"> <p>请求超时,无法获取数据</p> <button class="retry-btn" (click)="handleRetry()">重试</button> </div> `, styles: [` .retry-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 24px; background: #fff; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.15); z-index: 9999; } .retry-btn { padding: 8px 16px; margin-top: 12px; background: #1890ff; color: #fff; border: none; border-radius: 4px; cursor: pointer; } `] }) export class GlobalRetryComponent { showRetryBtn = false; constructor( private retryService: RetryService, private errorHandler: ErrorHandler ) { // 覆盖全局错误处理,捕获超时提示 const originalHandler = this.errorHandler.handleError; this.errorHandler.handleError = (error: any) => { if (error.message === '请求超时,请点击重试') { this.showRetryBtn = true; } else { originalHandler(error); } }; } handleRetry() { this.showRetryBtn = false; this.retryService.triggerRetry(); } }
最后将该组件添加到根组件模板中,确保全局可见。
关键RxJS操作符说明
timeout: 直接设置请求超时阈值,超时后抛出TimeoutError。defer: 延迟创建请求Observable,确保每次重试都是全新的请求实例,避免复用旧请求对象导致的异常。switchMap: 监听重试触发的事件流,当用户点击按钮时,切换到新的请求Observable完成重发。Subject: 作为事件总线,连接组件的点击操作与拦截器的请求重发逻辑,实现跨组件通信。
注意事项
- 需在Angular模块的
providers数组中注册拦截器,确保全局生效。 - 可根据业务需求调整超时时间、错误提示文案及重试按钮样式。
- 若需支持多并发请求的独立重试,可扩展
RetryService存储请求队列,为每个请求分配唯一标识。
内容的提问来源于stack exchange,提问作者vishva
相关产品推荐
相关产品推荐

