Angular 5 Interceptor - Only call second interceptor after failed retry on first interceptor

别来无恙 提交于 2019-12-07 10:05:26

问题


I am building an angular 5 app where I have 2 interceptors:

  • One to retry failed 504 requests
  • Another to show error messages to users about failed requests

I want that the second interceptor only gets called when the error is not 504 or when it is 504 and has already been retried by the first interceptor.

I have created a sample with both interceptors: https://stackblitz.com/edit/angular-interceptors-ckbvsb

Hope to get some assistance!

Thanks

UPDATE:

Thanks everyone for your assistance! I have ended up implementing it like this:

@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 })
        }
      })
  });
 }
}

回答1:


Your issue is the order in which you provide the two interceptors. You are providing I1 first and then I2. This means that a request will flow through I1 → I2, but the response will flow through I2 and only then through I1. So just switch the order:

@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 {
}



回答2:


Here is a one way how it can be done - apply it to your code:

// 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)
        )
    })
);



回答3:


I not sure that's the right way to handle this kind of things, interceptors are used to check requests, not responses, they dont care about the response returned because you pass the request with the .next before you even see the response.

seems more fitting to be done in a service that checks the response and then does another request to the other resource.

keep the retry interceptor in place and check the response you get on the service itself or the component to use a fallback URL.



来源:https://stackoverflow.com/questions/48865398/angular-5-interceptor-only-call-second-interceptor-after-failed-retry-on-first

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!