Reputation: 619
I am building an angular 5 app where I have 2 interceptors:
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 })
}
})
});
}
}
Upvotes: 4
Views: 3377
Reputation: 105439
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)
)
})
);
You can learn more about creating observables here.
Upvotes: 2
Reputation: 20033
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 {
}
Upvotes: 3
Reputation: 2232
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.
Upvotes: -2