【问题标题】:HTTP Interceptor send same request twiceHTTP 拦截器两次发送相同的请求
【发布时间】:2019-05-04 11:28:11
【问题描述】:

我正在使用 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: [ ... ]
})

这是我的 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!
    }

  }
}

通过 chrome 开发工具,我看到在网络选项卡中发送了两次相同的请求。在调试期间,我看到 searchProd 发送了一次 http 请求,但是当它被拦截时, next.handle() 被执行了两次。如何解决这个问题以便只发送一个请求?

编辑:这是网络标签中显示的内容

第一个请求

第二次请求

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>

组件.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
    })
  }

【问题讨论】:

  • 我非常怀疑同一个请求被发送了两次。我的猜测是您正在使用 CORS,因此您会看到标准的预取 OPTIONS 请求,然后是实际的 GET 请求。
  • 请检查网络选项卡中的标题部分,并验证两种情况下的请求方法是否都是获取
  • @JBNizet 后端在我使用 cors 包的 NodeJS 中。没有它,我将无法获取我的 api,因此是否可以通过在服务器端激活 cors 绕过来避免此问题?
  • 那么这意味着调用代码发送了两次请求,可能是通过两次订阅你的 observable。
  • 只需在您的pipe 通话末尾添加shareReplay(1)

标签: angular rxjs angular-httpclient angular-http-interceptors


【解决方案1】:

问题是我订阅了两次。一个在函数this.saveProdSearched(prodSearched); 中,一个在带有管道async 的模板中。我解决了这个问题,只需保存 saveProdSearched() 函数的结果,从模板中删除异步管道并显示 Product 数组中的结果

【讨论】:

    【解决方案2】:

    它也发生在我身上,但在我的情况下,我在两个不同组件的模板上使用 HttpClient 返回的同一 Observable 上的 async 管道,所以它订阅了 Observable 两次,这就是为什么它在HttpInterceptor 中拦截了两次请求。

    你需要检查你是否在同一个 Observable 上使用了 async 或 .subscribe() 2 次(HttpClient 返回的 Observable

    【讨论】:

      猜你喜欢
      • 2018-03-28
      • 2018-12-24
      • 2012-09-09
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多