6

I'm using an HTTP interceptor in order to add auth token to requests but when the http client fires the request, this is intercepted and sent twice

This is my HttpClient call

  searchProd(query: string, limit?: number): Observable<Product[]> {
    let _limit = limit || 5;
    return this.http.get<Product[]>(`${API_CONST.HOST}/${API_CONST.PRODUCT}?search=${query}&limit=${_limit}`);
  }

This is my app.module.ts

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; 
import { TokenInterceptor } from './auth/token.interceptor';
....

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
  ],
  providers: [
    ApiService,
    AuthGuardService,
    SettingsService,
    {
      provide : HTTP_INTERCEPTORS,
      useClass : TokenInterceptor,
      multi : true
    }
  ],
  entryComponents: [ ... ],
  bootstrap: [ ... ]
})

This is my token.interceptor.ts

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { AngularFireAuth } from '@angular/fire/auth';
import { Observable } from 'rxjs';
import { AuthGuardService } from './auth-guard.service';
import { API_CONST } from '../services/api/api.service';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  private no_auth_endpoints = [
    `${API_CONST.HOST}/${API_CONST.PRODUCT}`
  ]
  private token = null;
  constructor(public af: AngularFireAuth, private authGuard: AuthGuardService) {
    this.token = authGuard.getToken();
  }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const headersConfig = {
      'Authorization': `Bearer ${this.token}`
    };

    let isAuthEnpoint = true;
    this.no_auth_endpoints.forEach(endpoint => {
      if(request.url.includes(endpoint))
        isAuthEnpoint = false;
    })

    if (!request.headers.has('Authorization') && isAuthEnpoint) {
      const modified = request.clone({
        setHeaders : headersConfig
      });

      return next.handle(modified); //this line is executed twice!
    }
    else {
      return next.handle(request); //this line is executed twice!
    }

  }
}

Throught the chrome dev tools i see the same request sent twice in the network tab. During debugging I saw the http request send by searchProd once but when it's intecepted the next.handle() is executed twice. How to fix that in order to send only one request?

EDIT: This is what is shown in network tab

First request Request 1

Second request Request 2

EDIT2: This is the code where I call the searchProd(string) function.

component.html

<mat-form-field class="bottom-search-field">
    <input [formControl]="autoCompleteControl" type="text" placeholder="Aggiungi un prodotto"
      matInput [matAutocomplete]="auto">
    <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="onSelectionChanged($event)">
      <mat-option *ngFor="let item of searchResults | async; let index = index" [value]="item.description | titlecase">
        {{ item.description | titlecase}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>

component.ts

public autoCompleteControl = new FormControl();
...
ngOnInit(): void {
    this.searchResults = this.autoCompleteControl.valueChanges.pipe(
      startWith(''),
      switchMap(value => {
        if (value.length > 3) {
          let prodSearched = this.apiService.searchProd(value);
          prodSearched.pipe(share()); // ADDED PIPE SHARE
          this.saveProdSearched(prodSearched);
          return prodSearched;
        } else {
          return of(null);
        }
      })
    );
  }
  //This function save the last result inside of an array of Product
  private saveProdSearched(prodSearched: Observable<Product[]>) {
    prodSearched.subscribe(items => {
      this.lastSearch = items
    })
  }
19
  • 6
    I very much doubt the same request is sent twice. My guess is that you're using CORS, and that you are thus seeing the standard pre-fetch OPTIONS request followed by the actual GET request. Commented May 4, 2019 at 11:33
  • Please check the headers section in the network tab and verify whether the Request Method is Get in both the cases Commented May 4, 2019 at 11:42
  • 5
    Then it means the calling code is sending the request twice, probably by subscribing twice to your observable. Commented May 4, 2019 at 12:08
  • 1
    My guess is that you are using the async pipe on searchResults in two different places in your template. Try adding the shareReplay(1) operator call into your stream pipeline. Commented May 4, 2019 at 12:13
  • 2
    simply add shareReplay(1) at the end of your pipe call Commented May 4, 2019 at 16:50

2 Answers 2

2

The problem was that I was subscribing twice. One in the function this.saveProdSearched(prodSearched); and one in the template with pipe async. I solved the issue simply saving the result of the saveProdSearched() function, removing the async pipe from template and displaying the result from an array of Product

Sign up to request clarification or add additional context in comments.

Comments

0

it happened to me too, but in my case i'm using async pipe on a same Observable returned by HttpClient on 2 different components's templates, so it's subscribing to the Observable twice, that's why it's intercepting the request twice in the HttpInterceptor.

You need to check if you're using async or .subscribe() on the same Observable 2 times (the Observable returned by HttpClient)

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.