51

As you know it's possible to use Interceptors in new versions of Angular 4.

In mine, I want to cancel a request in interceptor in some conditions. So is it possible? Maybe what I should ask is: which way I should do that?

It'll also be OK if I find a way to rewrite some response to the request instead of canceling it.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Behnam Azimi
  • 2,260
  • 3
  • 34
  • 52
  • What do you mean by "rewrite some response"? It is easy to edit a request before handling it, if that's what you mean. – Jun Kang Sep 26 '17 at 19:03
  • The documentation has an example: https://angular.io/guide/http#caching – JB Nizet Sep 26 '17 at 19:05
  • I mentioned this because of some features in angularjs that I saw in https://stackoverflow.com/a/38926333/3534952. – Behnam Azimi Sep 26 '17 at 19:05
  • @JBNizet I reviewed the documentation over and over again! I think this one is not mentioned in documentation or maybe I can not see it! What I want I exactly is cancel a request or maybe rewrite another response instead of what will get from server. – Behnam Azimi Sep 26 '17 at 19:13
  • The documentation I linked to has the following comment: *A cached response exists. Serve it instead of forwarding the request to the next handler.* So it does return a cached response instead of actually sending the request to the server. – JB Nizet Sep 26 '17 at 19:18
  • But what if the cache not exist? @JBNizet – Behnam Azimi Sep 27 '17 at 05:37

8 Answers8

81

I think all you have to do to cut the interceptor chain is to simply return an empty Observable like so:

import { EMPTY } from 'rxjs';

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  if (stopThisRequest) {
    return EMPTY;
  }

  return next.handle(request);
}
Jon Koops
  • 8,801
  • 6
  • 29
  • 51
RVP
  • 2,330
  • 4
  • 23
  • 34
  • In a scenario, where let's say I have two rxJS requests executing simultaneously to the backend, and I want to stop one of them, how can I do that with interceptor? @RVP – Tanmoy Bhattacharjee Apr 12 '18 at 03:22
  • 2
    for RXJS 6 simply import { EMPTY } from 'rxjs' and return EMPTY. FYI, in rxjs EMPTY is different than empty. – Phil Aug 28 '18 at 18:26
  • How to cancel response while intercepting response in httpclient, Observable.empty() is not working – Ankit jhunjhunwala Nov 02 '18 at 08:15
  • @Codehan25 that logic you have to come up with your self. You can use DI to inject any service you want in the interceptor and base your logic on state available in your application – Sam Vloeberghs Aug 05 '19 at 06:16
  • Thanks, that is exactly what I was looking for, helped me a lot :) – Carsten Ennulat Nov 28 '19 at 13:49
  • @RVP I can able to break chain but I have to resolve this request with error before breaking, I tried throwerror() and pass Http error obj but didn't work, Can you help me on thiis? – Neeraj Rathod Apr 12 '20 at 18:45
  • If we had a reactive solution, two streams, how would it be done? - I thought of using next.handle(request).combineLatestWith(obs$).pipe(logic) – Vyache Jun 03 '22 at 15:51
12

This is just a slight variant of RVP's answer

import { NEVER } from 'rxjs';

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  if (stopThisRequest) {
    return NEVER;
  }

  return next.handle(request);
}

I used NEVER instead of EMPTY to avoid dealing with undefined values in my subscriptions (or promises).

Use NEVER if you don't want your subscription callback to be invoked

developer
  • 199
  • 2
  • 10
11

Inspired by @RVP answer I have found out that it's possible to cut the chain with an error in the same simple way using Observable.throw()

//...
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (stopThisRequestWithError) {
        return Observable.throw('Error message');
    } else {
        return next.handle(req);
    }
}

This avoids fulfilling response promises with undefined values.

veritas
  • 2,034
  • 1
  • 16
  • 30
  • In a scenario, where let's say I have two rxJS requests executing simultaneously to the backend, and I want to stop one of them, how can I do that with interceptor? – Tanmoy Bhattacharjee Apr 12 '18 at 03:23
  • 1
    This answer (using throwError in the current version of RxJS) was the only thing that worked for me. EMPTY, as others suggested, had some nasty side effects as the code that was waiting on the results never ran. – Marcel Lamothe Jan 23 '19 at 21:48
  • 2
    `throwError(...)` now – Akshay Mar 07 '19 at 12:06
  • @Codehan25 just a variable that I have came up with, you need to set the condition by yourself depending on needs. – veritas May 20 '19 at 10:55
2

Hey I think i am late to the party but wanna share some additional knowledge

If you wanna cancel requests after a certain timeout you can use rxjs timeout operator in intercepter, and it will work for every requests.

  intercept(req: HttpRequest<any>, next: HttpHandler):Observable<HttpEvent<unknown>> 
    {
    return next.handle(req).pipe(timeout(30000), 
    catchError((error: HttpErrorResponse) => {
      return throwError({ error: error.name, message: error.message});
    })) as Observable<HttpEvent<unknown>>
    }

1

To Angular 6, you need can user the following structure to return a empty Observable:

import {Observable} from 'rxjs';
import {empty} from 'rxjs/internal/Observer';

//...

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (stopThisRequest) {
        return Observable.create(empty);
    } else {
        return next.handle(req);
    }
}
Ângelo Polotto
  • 8,463
  • 2
  • 36
  • 37
0

@RVP's code will work, We can do one more thing for same.

add return only, it will also work

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
          if(helper.isTokenExpired(tokenVal)){
              return;
          }
        .
        . <{code}>
        .

    }
Kapil Thakkar
  • 840
  • 10
  • 17
  • 1
    This didn't work for me - got the error "You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable." – Marcel Lamothe Jan 23 '19 at 21:14
0

As suggested above, there is more optimal way to handle the error with custom response

import { throwError, Observable } from 'rxjs';
import { HttpEvent } from '@angular/common/http';

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  if (authFailedDummy(request)) {
    return throwError(new Error('Authorization error: The request did not go through'));
  }
  return next.handle(request);
}
Jiri Kralovec
  • 1,487
  • 1
  • 10
  • 18
-9
let sub = this.http.get(url, {headers: reqHeaders})
            .subscribe(
                (res) => {
                    res = res.json();
                }
            );

sub.unsubscribe();