1
votes

I am trying to intercept responses coming back from /api, catch them if they 401, execute a refresh session action, then retry the original HTTP call again (additionally preventing it from infinitely looping if it 401s again)

What I think I am doing in the code below is triggering the request with the http handler, subscribing to its events and if it fails on a 401, refresh then return an observable of the cloned request being actioned by the handler.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!request.url.startsWith('/api')) {
        return next.handle(request)
    }

    const cloned = request.clone()
    return next.handle(request)
        .pipe(
            catchError((error: any) => {
                if (error.status !== 401) {
                    return throwError(error)
                }
                return from(this.sessionService.refresh())
                    .pipe(map(() => next.handle(cloned)))
            })
        )
}

Any suggestions on how I could achieve what I am trying to?

2

2 Answers

0
votes

Probably a few syntax errors in this because im writing from mobile but this should get you started

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!request.url.startsWith('/api')) {
    return next.handle(request)
}

const cloned = request.clone()
return next.handle(request)
    .do((event: HttpEvent<any>) =>
        return from(this.sessionService.refresh())
               .pipe(map(() => next.handle(cloned)))
        }), (err: any) => {
             if (err instanceof HttpResponse) {
                  if(err.status === 401){
                       return throwError(error);
                  }
        }
    )
}
0
votes

The answer was to use switctMap rather than map

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
{
    if (!request.url.startsWith('/api')) {
        return next.handle(request)
    }

    const cloned = request.clone()
    return next.handle(request)
        .pipe(
            catchError((error: any) => {
                if (error.status !== 401) {
                    return throwError(error)
                }
                return from(this.sessionService.refresh())
                    .pipe(switchMap(() => next.handle(cloned)))
        })
    )
}

However, I opted for an alternative approach where I check if I have a session before the request happens, injecting a refresh action if required.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (
        !request.url.startsWith('/api') || 
        this.sessionService.isValid
    ) {
        return next.handle(request)
    }

    return from(this.sessionService.refresh())
        .pipe(switchMap(() => next.handle(request)))
}