Angular 5 Interceptor - 在第一个拦截器上重试失败后才调用第二个拦截器

时间:2018-02-19 11:38:49

标签: angular rxjs interceptor

我正在构建一个角度为5的应用程序,其中有2个拦截器:

  • 重试失败的504次请求
  • 另一个向用户显示有关失败请求的错误消息

我希望第二个拦截器仅在错误不是504或者它是504并且已经被第一个拦截器重试时被调用。

我创建了一个包含两个拦截器的示例:https://stackblitz.com/edit/angular-interceptors-ckbvsb

希望得到一些帮助!

由于

更新:

感谢大家的帮助!我最终以这样的方式实现它:

@Injectable()
export class I1 implements HttpInterceptor {
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
 console.log('intercepted I1');

 return next.handle(req)
  .retryWhen(error => {
    return error
      .mergeMap((err, i) => {
        if (i > 0) return Observable.throw(err)
        if (err instanceof HttpErrorResponse && err.status === 504) { // timeout
          return Observable.of(err).delay(5000);
        } else {
          return Observable.throw({ error: 'No retry', cause: err })
        }
      })
  });
 }
}

3 个答案:

答案 0 :(得分:3)

您的问题是您提供两个拦截器的顺序。你首先提供I1然后提供I2。这意味着请求将流经I1→I2,但响应将流经I2,然后流经I1。所以只需切换顺序:

@NgModule({
    imports: [BrowserModule, HttpClientModule],
    declarations: [AppComponent],
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: I2,               // <-- I2 first
            multi: true
        },
        {
            provide: HTTP_INTERCEPTORS,
            useClass: I1,               // <-- And only then I1
            multi: true
        }
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}

答案 1 :(得分:2)

以下是一种如何完成的方法 - 将其应用于您的代码:

// an observable producer that produces an error
const producer = (obs) => {
    obs.next(0);
    obs.error(new Error('504'));
};

const i1 = Observable.create(producer).pipe(
    retryWhen((errors) => {
        return errors.pipe(
            scan((a, v, i) => {
                a.unshift(v);
                return a;
            }, []),
            map((v) => {
                if (!v[0].message.includes('504') || v.length > 1) {
                    throw v[0];
                } else {
                    return v[0].message;
                }
            }),
            delay(2000)
        )
    })
);

答案 2 :(得分:-1)

我不确定这是处理这类事情的正确方法,拦截器用于检查请求,而不是响应,他们不关心返回的响应,因为您在查看响应之前使用.next传递请求。

似乎更适合在检查响应的服务中完成,然后对另一个资源执行另一个请求。

保留重试拦截器并检查您对服务本身或组件的响应以使用回退URL。