Angular 5:HttpInterceptor响应拦截器遇504超时重试问题
Hey there! Let's break down why you're seeing a status code of 0 instead of the expected 504, and how to fix it alongside your Auth interceptor.
为什么状态码会是0?
When Angular encounters a network-level error (like a timeout, CORS issue, or the browser aborting the request before receiving a full response), the HttpErrorResponse will show a status of 0—even if your browser's dev tools display a 504 Gateway Timeout. This happens because the browser doesn't expose the full server response details to Angular in these edge cases.
The twist with your scenario is that your Auth interceptor is interacting with this error flow, which might be altering how the error is passed through the interceptor chain.
修复步骤
1. 确保拦截器顺序正确
Angular runs interceptors in the order you provide them for request handling, and in reverse order for response/error handling. For your retry logic to work with authenticated requests:
- Add your Auth interceptor first (so it attaches the auth header before the request reaches the retry logic)
- Add your retry interceptor second (so it catches errors after the Auth interceptor has processed the response)
Example in your app module:
providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: RetryInterceptor, multi: true } ]
2. 修正Auth拦截器的错误处理
If your Auth interceptor uses catchError, make sure it only handles specific errors (like 401 Unauthorized) and re-throws all other errors without modifying them. A common mistake is overwriting the error object, which can wipe out status code details or set status to 0.
Bad example (avoid this):
catchError(err => { if (err.status === 401) { // Handle token refresh/login redirect } // ❌ This replaces the original error with a status 0 response return throwError(() => new HttpErrorResponse({ status: 0 })); })
Good example:
catchError(err => { if (err.status === 401) { // Handle your auth logic here (e.g., refresh token) } // ✅ Re-throw the original error so downstream interceptors can process it return throwError(() => err); })
3. 优化重试拦截器的错误判断
Since you might get status: 0 even for a 504 error, update your retry logic to check for both cases, plus additional error context (like error messages or event type):
import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError, of } from 'rxjs'; import { mergeMap, delay, take, retryWhen } from 'rxjs/operators'; @Injectable() export class RetryInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(request).pipe( retryWhen(errors => { return errors.pipe( mergeMap((err: HttpErrorResponse) => { // Check for 504 OR status 0 (network/timeout error) with relevant context const shouldRetry = err.status === 504 || (err.status === 0 && (err.message.includes('timeout') || err.error instanceof ProgressEvent)); if (shouldRetry) { // Retry after 1 second, adjust delay as needed return of(err).pipe(delay(1000)); } // Don't retry, pass the error through return throwError(() => err); }), take(3) // Limit to 3 retries, adjust as needed ); }) ); } }
4. 检查CORS配置(如果适用)
If your server returns a 504 but Angular still gets status: 0, verify your server's CORS settings. Ensure the Access-Control-Expose-Headers header includes any necessary response headers, and that the server allows the client to access the 504 status code. Some servers block exposing error status codes via CORS by default.
总结
The core issue is likely a combination of Angular's handling of network errors and your Auth interceptor altering the error flow. By fixing the interceptor order, ensuring errors are passed through unmodified, and expanding your retry logic to account for status: 0 cases, you should get your timeout retry functionality working as expected.
内容的提问来源于stack exchange,提问作者HobojoeBr

