首页 > 解决方案 > Angular HttpInterceptor 不适用于 forkJoin

问题描述

我有服务从 Observable 和 HttpInterceptor 类型获取令牌,以使用它在每个 http 请求中注入令牌。问题是它适用于单个请求,但如果我使用 forkJoin 我不会得到任何响应。

拦截器代码

import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { AppService } from './app.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(
    private service: AppService
  ) { }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.service.token$.pipe(
      map((token: string) => {
        if (token) {
          const headers = req.headers.set('Authorization', `Bearer ${token}`);
          console.log(`Request for url ${req.url}`);
          req = req.clone({
            headers: headers
          });
        }
        return req;
      }
      ),
      switchMap(newReq => next.handle(newReq))
    )
  }
}

和简单的两个请求

  getUsers() {
    return this.http.get<any[]>(`https://jsonplaceholder.typicode.com/users`);
  }

  getPosts() {
    return this.http.get<any[]>(`https://jsonplaceholder.typicode.com/posts`);
  }

并且在组件中

// Single One will work
 this.appService.getPosts().subscribe(res => console.warn(res));

// Will not work
    forkJoin([this.appService.getPosts(), this.appService.getUsers()])
      .subscribe(([posts, users]) => {
        console.log(posts, users);
      });

我在示例中重新生成了错误,您可以检查它 ht​​tps://stackblitz.com/edit/angular-kpxvej

只有当我在拦截器中添加 take(1) 时它才会起作用,但它不会是我想要的东西,因为我得到了一个新的令牌值不会使用它。

而在其他情况下,如果 token 只是一个字符串,它将像那样工作

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.service.getToken();
    const headers = req.headers.set('Authorization', `Bearer ${token}`);
    console.log(`Request for url ${req.url}`);
    req = req.clone({
      headers: headers
    });
    return next.handle(req);
  }

标签: javascriptangulartypescriptrxjsangular6

解决方案


据我了解,在拦截器中,如果您使用令牌作为 Observable 和 switchMap,您最终可能会取消另一个请求。

您的具体示例将变为:(getUsers 触发 -> 拦截添加令牌和 getPosts 触发 -> 拦截添加令牌) -> switchMap(取消先前拦截的请求) -> 只有 1 个请求实际触发。

forkJoin 需要两个 observables 都完成才能触发,所以你的情况是一个得到服务器响应,另一个保持沉默。

您可以使用 mergeMap 而不是 switchMap(它不会取消请求),但是最好的解决方案是在调用服务函数之前使用 switchMap。

此外,将令牌制作为字符串而不是可观察的也是合理的,因为它在会话期间很少更改,您可以使用 set-get to localStorage 来确保它是最新的。

希望能帮助到你。


推荐阅读