Angular - 重试具有特定错误状态的请求的 HTTP 拦截器?
Angular - HTTP interceptor to retry requests with specific error status?
我正在尝试使用拦截器来处理 http 错误并重试特殊错误状态,在我的例子中是状态代码 502。
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retryWhen(errors => {
return errors
.pipe(
mergeMap(error => (error.status === 502) ? throwError(error) : of(error)),
take(2)
)
})
)
}
但它不工作,而当我以这种方式使用 retry()
时,它工作得很好
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retry(2),
catchError((error: HttpErrorResponse) => {
return throwError(error);
})
)
}
试试下面的代码。你应该反过来做。
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retryWhen(errors => {
return errors
.pipe(
mergeMap(error=>error.status === 502?timer(0):throwError(error)),
take(2)
)
}),
catchError((error: HttpErrorResponse) => {
return throwError(error);
})
)
}
出于自己的兴趣,我采用了您的方法并对其进行了一些扩展。
首先是创建一种自定义运算符:
import { timer, throwError, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
export interface RetryParams {
maxAttempts?: number;
scalingDuration?: number;
shouldRetry?: ({ status: number }) => boolean;
}
const defaultParams: RetryParams = {
maxAttempts: 3,
scalingDuration: 1000,
shouldRetry: ({ status }) => status >= 400
}
export const genericRetryStrategy = (params: RetryParams = {}) => (attempts: Observable<any>) => attempts.pipe(
mergeMap((error, i) => {
const { maxAttempts, scalingDuration, shouldRetry } = { ...defaultParams, ...params }
const retryAttempt = i + 1;
// if maximum number of retries have been met
// or response is a status code we don't wish to retry, throw error
if (retryAttempt > maxAttempts || !shouldRetry(error)) {
return throwError(error);
}
console.log(`Attempt ${retryAttempt}: retrying in ${retryAttempt * scalingDuration}ms`);
// retry after 1s, 2s, etc...
return timer(retryAttempt * scalingDuration);
})
);
然后您可以基于此运算符构造一个拦截器,如下所示:
@Injectable()
export class RetryInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { shouldRetry } = this;
return next.handle(request)
.pipe(retryWhen(genericRetryStrategy({
shouldRetry
})));
}
private shouldRetry = (error) => error.status === 502;
}
您可以看到它正在运行 in this blitz
我正在尝试使用拦截器来处理 http 错误并重试特殊错误状态,在我的例子中是状态代码 502。
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retryWhen(errors => {
return errors
.pipe(
mergeMap(error => (error.status === 502) ? throwError(error) : of(error)),
take(2)
)
})
)
}
但它不工作,而当我以这种方式使用 retry()
时,它工作得很好
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retry(2),
catchError((error: HttpErrorResponse) => {
return throwError(error);
})
)
}
试试下面的代码。你应该反过来做。
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.pipe(
retryWhen(errors => {
return errors
.pipe(
mergeMap(error=>error.status === 502?timer(0):throwError(error)),
take(2)
)
}),
catchError((error: HttpErrorResponse) => {
return throwError(error);
})
)
}
出于自己的兴趣,我采用了您的方法并对其进行了一些扩展。
首先是创建一种自定义运算符:
import { timer, throwError, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
export interface RetryParams {
maxAttempts?: number;
scalingDuration?: number;
shouldRetry?: ({ status: number }) => boolean;
}
const defaultParams: RetryParams = {
maxAttempts: 3,
scalingDuration: 1000,
shouldRetry: ({ status }) => status >= 400
}
export const genericRetryStrategy = (params: RetryParams = {}) => (attempts: Observable<any>) => attempts.pipe(
mergeMap((error, i) => {
const { maxAttempts, scalingDuration, shouldRetry } = { ...defaultParams, ...params }
const retryAttempt = i + 1;
// if maximum number of retries have been met
// or response is a status code we don't wish to retry, throw error
if (retryAttempt > maxAttempts || !shouldRetry(error)) {
return throwError(error);
}
console.log(`Attempt ${retryAttempt}: retrying in ${retryAttempt * scalingDuration}ms`);
// retry after 1s, 2s, etc...
return timer(retryAttempt * scalingDuration);
})
);
然后您可以基于此运算符构造一个拦截器,如下所示:
@Injectable()
export class RetryInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { shouldRetry } = this;
return next.handle(request)
.pipe(retryWhen(genericRetryStrategy({
shouldRetry
})));
}
private shouldRetry = (error) => error.status === 502;
}
您可以看到它正在运行 in this blitz