Angular HttpInterceptor无法与forkJoin一起使用 [英] Angular HttpInterceptor not working with forkJoin

查看:86
本文介绍了Angular HttpInterceptor无法与forkJoin一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有Service可以从Observable类型获取令牌,而HttpInterceptor可以将其用于在每个http请求中注入令牌. 事实是,对单个请求它可以正常工作,但是如果我使用forkJoin,我将不会得到任何响应.

I have Service to get the token from type Observable and HttpInterceptor to use it to inject the token in every http request. The thing is it works fine with a single request but if i used forkJoin i will not get any response back.

拦截器代码

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

我重现了示例错误,您可以检查一下 https://stackblitz.com/edit/angular-kpxvej

I re-produced the error on example you can check it https://stackblitz.com/edit/angular-kpxvej

仅当我在拦截器中添加take(1)时,它将起作用,但那不是我想要的东西,因为我为令牌获得了一个新值,将不会使用它.

It will work only if i add take(1) in the interceptor but then it will not be the thing i want because i got a new value for the token will not use it.

,在其他情况下,如果令牌只是一个字符串,则可以使用 像这样

and in other case if token was just a string will work like that

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

推荐答案

据我所知,在拦截器中,如果您将标记用作Observable和switchMap,则可能会导致一个请求取消另一个请求.

From my understanding, in the interceptor if you make use of token as Observable and switchMap, you may end up one request cancel the other.

您的特定示例将变成:(getUsers触发->拦截添加令牌,而getPosts触发->拦截添加令牌)-> switchMap(取消先前被拦截的请求)->实际上只有1个请求触发.

Your specific example would turn into: (getUsers fires -> intercepts adds token & getPosts fires -> intercept adds token) -> switchMap (cancel the previous intercepted request) -> only 1 request actually fires.

forkJoin要求完成两个可观察对象才能触发,因此您的情况是一个得到服务器响应,另一个保持沉默.

forkJoin requires both observables to be completed in order to fire, so your situation is one gets server response, the other remains silent.

您可以使用mergeMap代替switchMap(这不会取消请求),但是最好的解决方案是在调用services函数之前使用switchMap.

You can use mergeMap instead of switchMap (which won't cancel the request), however the best solution would be using switchMap prior to calling the services function.

另外,将令牌作为字符串而不是可观察的是合理的,因为它在会话期间很少更改,并且可以使用set-get到localStorage来确保它是最新的.

Also, it would be reasonable to make token as a string rather than observable as it rarely changes during a session, and you can make use of set-get to localStorage to make sure it's up-to-date.

希望有帮助.

这篇关于Angular HttpInterceptor无法与forkJoin一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆