27

I am writing interceptors such that I don't have to handle the headers in every service calling my web api. The problem with this is that 99% of my calls require 1 specific set of headers, but the other 1% only require 1 of the headers and will not work with the others present. With this being known my idea is to make 2 interceptors, the first will add the 1 header that they all use and the second will add the rest of the headers, with the second excluding the 1%.

The following is how I am going about excluding the 1%, which works, but I want to see if there is a better way of going about this:

intercept(request: HttpRequest<any>, next:HttpHandler: Observable<HttpEvent<any>> {
  let position = request.url.indexOf('api/');
  if (position > 0){
    let destination: string = request.url.substr(position + 4);
    let matchFound: boolean = false;

    for (let address of this.addressesToUse){
      if (new RegExp(address).test(destination)){
        matchFound = true;
        break;
      }
    }

    if (!matchFound){
      ...DO WORK to add the headers
    }
  }
dmoore1181
  • 1,793
  • 1
  • 25
  • 57
  • If it's 1%, it may be worth looking into making a [seperate HTTP client](https://www.bennadel.com/blog/3589-http-interceptors-are-an-anti-pattern-that-create-hidden-dependencies-and-unnecessary-complexity-in-angular.htm). – Phix Apr 04 '19 at 18:02
  • 1
    Does this answer your question? [Disable Angular HttpInterceptor for some call](https://stackoverflow.com/questions/60424072/disable-angular-httpinterceptor-for-some-call) – fasfsfgs Aug 18 '21 at 14:27

7 Answers7

60

Update from Angular 12, use "context", see this SO

I suggest that, in spite of check the request, you can use the header to add a "skip" property, if the header has the skip property, simple return the reqs

export class CustomInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.headers.get("skip"))
           return next.handle(req);
      
        ....
    }
}

And you make all the calls you need "skip" the interceptor like

this.http.get(url, {headers:{skip:"true"}});
enne87
  • 2,221
  • 8
  • 32
  • 61
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • Sorry for my stupid. I can't find the options `{headers:{skip:"true"}` online. – Bigeyes Aug 13 '21 at 14:23
  • 1
    You can add any header you want. I like the name "skip", but you can choose what ever (e.g. in some platform for e-comerce you add some like API-KEY) – Eliseo Aug 14 '21 at 17:39
24

after checking for req.headers.get("skip") as Eliseo suggested, I'd recommend removing this header from request since it's Angular-related only and it should not be transmitted to the API (actually it can cause issues)

const skipIntercept = request.headers.has('skip');

if (skipIntercept) {
    request = request.clone({
        headers: request.headers.delete('skip')
    });
}
Ihor
  • 571
  • 6
  • 10
18

What I wound up doing is having an array of urls (in Regex Format) that I did not want to be used in the interceptor like so:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AddCustomHeadersInterceptor implements HttpInterceptor {
  urlsToNotUse: Array<string>;

  constructor(
  ) {

    this.urlsToNotUse= [
      'myController1/myAction1/.+',
      'myController1/myAction2/.+',
      'myController1/myAction3'
    ];
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (this.isValidRequestForInterceptor(request.url)) {
      let modifiedRequest = request.clone({
        setHeaders: {
          //DO WORK HERE
        }
      });

      return next.handle(modifiedRequest);
    }
    return next.handle(request);
  }

  private isValidRequestForInterceptor(requestUrl: string): boolean {
    let positionIndicator: string = 'api/';
    let position = requestUrl.indexOf(positionIndicator);
    if (position > 0) {
      let destination: string = requestUrl.substr(position + positionIndicator.length);
      for (let address of this.urlsToNotUse) {
        if (new RegExp(address).test(destination)) {
          return false;
        }
      }
    }
    return true;
  }
}
dmoore1181
  • 1,793
  • 1
  • 25
  • 57
14

When created by default, HttpClient will use interceptor. If you want to avoid this, you can create another instance of HttpClient using constructor.

@Injectable()
class Service {
  private customHttpClient: HttpClient;

  constructor(backend: HttpBackend) {
    this.customHttpClient = new HttpClient(backend);
  }
}

The customHttpClient instance will not use the interceptor.

Myk Willis
  • 12,306
  • 4
  • 45
  • 62
1

You can try to extent HttpClient instead of using Interceptors.

In an Interceptor World every request is stopped - massaged (headers are added) - before executed.

In a HttpClient World it would be taken care at the time of Client object instantiation.

If you deem it necessary, you can consider having different variants per se, HttpClient99Percent variant, HttpClientOnePercent variant etc.

Below link can give you a head start:

https://medium.com/@admin_87321/extending-angular-httpclient-6b33a7a1a4d0

takrishna
  • 4,884
  • 3
  • 18
  • 35
0

update of Андрей Керничный's answer

import { Injectable } from '@angular/core';
import { HttpClient, HttpBackend } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class CartService {
  private customHttpClient: HttpClient;

  constructor(private http: HttpClient, backend: HttpBackend) { 
    this.customHttpClient = new HttpClient(backend);
  }

  getZohoItems() {
    // call zoho url
    return this.customHttpClient.get('http://zoho.com/api/orders/');
  }

  getItems() {
    // call localhost:8000 url
    return this.http.get('/api/orders/');
  }
}
suhailvs
  • 20,182
  • 14
  • 100
  • 98
0
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.indexOf('Url that you want to hide') === -1) {
  this.spinner.show();
  return next.handle(req).pipe(
    finalize(() => this.spinner.hide())
  );
}
if (req.url.indexOf('Url that you want to hide') !== -1) {
  this.spinner.hide();
}
return next.handle(req);

}

  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 01 '22 at 02:53