HTTP Interceptor отправляет один и тот же запрос дважды - PullRequest
1 голос
/ 04 мая 2019

Я использую перехватчик HTTP для добавления токена авторизации к запросам, но когда http-клиент запускает запрос, он перехватывается и отправляется дважды

Это мой вызов HttpClient

  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}`);
  }

Это мой 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: [ ... ]
})

Это мой токен.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!
    }

  }
}

С помощью инструментов разработчика Chrome я вижу один и тот же запрос, отправленный дважды на вкладке сети. Во время отладки я видел http-запрос, отправленный searchProd один раз, но когда он был перехвачен, next.handle () выполняется дважды. Как это исправить, чтобы отправить только один запрос?

РЕДАКТИРОВАТЬ: Это то, что показано на вкладке сети

Первый запрос Request 1

Второй запрос Request 2

EDIT2: это код, в котором я вызываю функцию searchProd (string).

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
    })
  }

1 Ответ

0 голосов
/ 04 мая 2019

Проблема была в том, что я подписывался дважды.Один в функции this.saveProdSearched(prodSearched); и один в шаблоне с трубкой async.Я решил проблему, просто сохранив результат функции saveProdSearched(), удалив асинхронный канал из шаблона и отобразив результат из массива Product

...