angular - Angular 会自动重新发送失败的 http 请求 3 次以上 - 为什么?
问题描述
看来这可能是我的错,但我不知道为什么。HttpClient
post
每当我使用或在我的应用程序中的任何位置发送 HTTP 请求get
并接收到非 2xx 响应时,该请求都会立即重试 3 次(总共 4 次)。我不想要这种行为,如果关闭,我会尝试关闭。
如果我已经通过管道进入我的可观察管道,这是我所期望的行为retry
,但我没有。我确实有一些拦截器用于身份验证和错误处理,但我看不到它们中的任何会导致这种行为的东西。任何人都可以提出一种方法来追踪导致这些重试的原因吗?
编辑:原来这肯定是由我的身份验证拦截器引起的。
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse } from '@angular/common/http';
import { throwError, Observable, BehaviorSubject, of, from } from 'rxjs';
import { catchError, filter, take, switchMap, finalize } from 'rxjs/operators';
import { AuthService } from './auth.service';
import { environment } from 'src/environments/environment';
/**
* Disables this interceptor for a given HTTP request
* Usage: this.http.get(`${environment.apiBase}someEndpoint`, { headers: new HttpHeaders().set(SkipAuthorizationHeader, '') })
*/
export const SkipAuthorizationHeader = 'X-Skip-Authorization-Handler';
@Injectable()
export class AuthorizationInterceptor implements HttpInterceptor {
private refreshTokenInProgress = false;
private readonly refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(private readonly auth: AuthService) { }
public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Abort if the request has instructed us via a custom header to do so
if (req.headers.has(SkipAuthorizationHeader)) {
// Delete the temporary header otherwise ASP.NET might get spooked by the unrecognised header
const headers = req.headers.delete(SkipAuthorizationHeader);
return next.handle(req.clone({ headers }));
}
if (!req.headers.has('Content-Type')) {
req = req.clone({
headers: req.headers.set('Content-Type', 'application/json')
});
}
req = this.addAuthenticationToken(req);
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error && error.status === 401 && this.auth.canAttemptTokenRenewal) {
// 401 errors are most likely going to be because we have an expired token that we need to refresh.
if (this.refreshTokenInProgress) {
// If refreshTokenInProgress is true, we will wait until refreshTokenSubject has a non-null value
// which means the new token is ready and we can retry the request again
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap(() => next.handle(this.addAuthenticationToken(req)))
);
} else {
this.refreshTokenInProgress = true;
// Set the refreshTokenSubject to null so that subsequent API calls will wait until the new token has been retrieved
this.refreshTokenSubject.next(null);
return this.refreshAccessToken().pipe(
switchMap((success: boolean) => {
this.refreshTokenSubject.next(success);
return next.handle(this.addAuthenticationToken(req));
}),
// When the call to refreshToken completes we reset the refreshTokenInProgress to false
// for the next time the token needs to be refreshed
finalize(() => this.refreshTokenInProgress = false)
);
}
} else {
throwError(error);
return next.handle(req);
}
})
);
}
private refreshAccessToken(): Observable<any> {
return from(this.auth.renewTokensAsync());
}
private addAuthenticationToken(request: HttpRequest<any>): HttpRequest<any> {
// If we do not have a token yet then we should not set the header.
// Here we could first retrieve the token from where we store it.
if (!this.auth.accessToken) {
return request;
}
// If you are calling an outside domain then do not add the token.
if (!request.url.match(environment.authDomainPattern)) {
return request;
}
return request.clone({
headers: request.headers.set('Authorization', `Bearer ${this.auth.accessToken}`)
});
}
}
此代码似乎导致所有失败的 HTTP 请求重试 3 次。我总是与 rxjs 斗争,所以这显然是我在这里所做的坏事,但我看不出是什么。
解决方案
这里
return next.handle(req).pipe(
在这里添加
} else {
throwError(error);
return next.handle(req);
}
else
当您收到错误时调用块!= 401。req
是已提出的原始请求。所以在这里你正在做同样的错误请求。
我不确定它是否应该可以到达,因为我不记得是什么throwError
(自从我使用角度以来已经有一段时间了)
推荐阅读
- c# - 表示类型 Func
通过反射 - vba - Excel VBA 从值为 TRUE 的列表中选择工作表
- rinsim - 如何在 RinSim 中从仓库中移除包裹
- javascript - 当行以冒号结尾时,Javascript 不会抛出“未定义”错误
- postgresql - 从地理与经度和纬度字段中获取 lon/lat 的性能差异
- c# - 使用 Url.Action 时的路由
- sql - 将备份文件从主服务器复制到辅助服务器
- extentreports - 如何使用范围报告创建具有类及其相应测试的报告
- c# - 与 C# 交互时降低球的质量
- c# - 构造类对象时如何防止 ASP.NET 绑定引擎不必要地调用只读属性?