首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >forkJoin不支持Angular HttpInterceptor

forkJoin不支持Angular HttpInterceptor
EN

Stack Overflow用户
提问于 2018-05-31 06:22:54
回答 3查看 1.3K关注 0票数 1

我让Service从类型Observable获取令牌,让HttpInterceptor使用它在每个http请求中注入令牌。问题是,它可以很好地处理单个请求,但如果我使用forkJoin,我将得不到任何响应。

拦截器代码

代码语言:javascript
复制
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))
    )
  }
}

像这样两个简单的请求

代码语言:javascript
复制
  getUsers() {
    return this.http.get<any[]>(`https://jsonplaceholder.typicode.com/users`);
  }

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

并且在组件中

代码语言:javascript
复制
// 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);
      });

我在example中重现了这个错误,你可以在https://stackblitz.com/edit/angular-kpxvej中查看它

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

在其他情况下,如果token只是一个字符串,那么它的工作方式是这样的

代码语言:javascript
复制
  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);
  }
EN

回答 3

Stack Overflow用户

发布于 2018-08-22 08:12:34

据我所知,在拦截器中,如果您使用token作为Observable和switchMap,您可能会以一个请求取消另一个请求而结束。

您的特定示例将变成:(getUsers触发->拦截添加令牌& getPosts触发->拦截添加令牌) -> switchMap (取消上一个被拦截的请求) ->仅实际触发1个请求。

forkJoin需要完成两个可观察对象才能触发,所以您的情况是一个获得服务器响应,另一个保持沉默。

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

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

希望能有所帮助。

票数 3
EN

Stack Overflow用户

发布于 2021-09-25 16:46:24

这可能有点晚了,但除了Ngoc Nam Nguyen anwser (这很有帮助)之外。对我来说,这有助于在接收器中切换到mergeMap,并使用take one来确保任何令牌更改不会在以后影响拦截器。所以我最终得到了一个像这样的拦截器:

代码语言:javascript
复制
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return this.authFacade.token$.pipe(
  take(1),
  mergeMap((token: string) => {
    if (token && req.method === 'POST') {
      const request = req.clone({
        setHeaders: { Authorization: `Bearer ${token}` },
      });
      return next.handle(request);
    }
    return next.handle(req);
  })
);
}

因此,我能够将该标记保留为可观察性,我认为这会更好一些。

票数 1
EN

Stack Overflow用户

发布于 2018-08-22 00:53:38

我通过将令牌从Observable转换为字符串解决了这个问题。我通过这样做解决了这个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50614121

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档