5

How do I handle cancelled requests in http interceptor? I have tried various methods from SO, but none of them seem to catch it.

This is how my interceptor is,

public intercept(req: HttpRequest<any>, next: HttpHandler) {
        const xyz = this._cookieService.get('xyz');
        const abc = this._cookieService.get('abc');

        let authReq;
        if (jwt === "undefined" || jwt === undefined) {
            authReq = req.clone({ headers: req.headers.set('Authorization', xyz) });
        } else {
            authReq = req.clone({setHeaders: { Authorization: 'bearer ' + abc } });
        }

        return next
            .handle(authReq)
            .pipe(
                catchError((err: HttpErrorResponse) => this.catchErrorHandler(err))
            );
    }

I have tried the do, finalize methods as well. Its that, my auth expires, and all the requests after that just collapse one by one, and the page breaks. I would like to handle it with code, so that the page doesn't break. Methods I have tried: https://stackoverflow.com/a/50620910/6630504 https://stackoverflow.com/a/55756885/6630504

My requests

5
  • Please share exactly how you are cancelling requests in your code. Also please share how you are handling errors in the service where this failing HttpClient is causing issues. Commented Sep 4, 2019 at 3:54
  • I am not deliberately canceling the code. The browser cancels the code, in my case if the auth expires. Commented Sep 5, 2019 at 15:24
  • Have you determined why the requests are being cancelled? It's very difficult to help resolve this issue if there isn't a working example or a process to replicate this issue. Commented Sep 5, 2019 at 15:36
  • I have similar problem. I have counter realted to count simualtenous calls to show wait screen. Now when call is cancelled spinner stay showing because one call has started but never ending. Or seems like that. Have you managed to solve your problem? Commented Mar 11, 2021 at 9:37
  • There is fix in angular 11.2 github.com/angular/angular/issues/22324 Commented Mar 11, 2021 at 11:19

4 Answers 4

3

There is an RxJS operator called finalize.

Returns an Observable that mirrors the source Observable, but will call a specified function when the source terminates on complete or error. The specified function will also be called when the subscriber explicitly unsubscribes.

    return next
        .handle(authReq)
        .pipe(
            catchError((err: HttpErrorResponse) => this.catchErrorHandler(err)),
            finalize(() => console.log('finalize'))
        );
Sign up to request clarification or add additional context in comments.

Comments

1

I was wondering the same thing for some time now and decided to look into it today.

When logging a cancelled request, the error looks like this:

{
    "headers": {
        "normalizedNames": {},
        "lazyUpdate": null,
        "headers": {}
    },
    "status": 0,
    "statusText": "Unknown Error",
    "url": "https://localhost:7258/api/company/test-exception",
    "ok": false,
    "name": "HttpErrorResponse",
    "message": "Http failure response for https://localhost:7258/api/company/test-exception: 0 Unknown Error",
    "error": {
        "isTrusted": true
    }
}

Notice the headers are empty and the status code is 0?

I found this when I search for what status code 0 means:

Practically speaking, status==0 for a failed XmlHttpRequest should be considered an undefined error.

this code could be the result of an error that happened even before the server is contacted.

Answer by whitneyland at What does it mean when an HTTP request returns status code 0?

While we will still need to determine the cause of the status 0, we could simply catch this error by:

next
  .handle(req)
  .pipe(
  catchError((err) => {
    if (err.status == 0) {
      // handle cancelled request here
      console.log(err);
    }
  }
})

Comments

0

Try this interceptor:

@Injectable()
export class RequestInterception implements HttpInterceptor {
  public constructor() { }

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const token = '';
    const currentLanguage = 'en';
    let headers;

    if (token) {
      headers = new HttpHeaders({
        "X-MDM-Token": token,
        "Accept-Language": currentLanguage
      });
    }

    request = request.clone({
      headers: headers,
      url: request.url || environment.serverUrl
    });

    return next.handle(request).pipe(
      map((event: any) => {

        if (event.status < 200 || event.status >= 300) {
          return Observable.throw(event);
        }

        return event;
      }),

      catchError((response: HttpErrorResponse, request) => {
        switch (response.status) {
          case 401:
            //
            break;
        }
        return throwError("Ошибка сервера RequestInterception!");
      })
    );
  }
}

If client canceled http request you will get 499 http code, it will be caught by:

if (event.status < 200 || event.status >= 300) {
      return Observable.throw(event);
}

1 Comment

Thanks for answering. But this is not catching the request in it. Since it is canceled, it does not have a status code.
0

I`ve doned it like this:

Interceptor code:

...
return next.handle(request)
  .pipe(
    onCancelled(() => {
      // cancelled request callback
    }),
  );
...

onCancelled function

function onCancelled<T>(callback: () => void) {
  return (obs: Observable<T>) => {
    let cancelled = true;
    return new Observable<T>(subscriber => {
      const sub = obs.subscribe(
        value => {
          if (value instanceof HttpResponse) cancelled = false;
          subscriber.next(value);
        },
        err => {
          cancelled = false;
          subscriber.error(err);
        },
        () => {
          cancelled = false;
          subscriber.complete();
        });
      return () => {
        if (cancelled) callback();
        sub.unsubscribe();
      };
    });
  };
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.