javascript - 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);
});
我在示例中重新生成了错误,您可以检查它 https://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);
}
解决方案
据我了解,在拦截器中,如果您使用令牌作为 Observable 和 switchMap,您最终可能会取消另一个请求。
您的具体示例将变为:(getUsers 触发 -> 拦截添加令牌和 getPosts 触发 -> 拦截添加令牌) -> switchMap(取消先前拦截的请求) -> 只有 1 个请求实际触发。
forkJoin 需要两个 observables 都完成才能触发,所以你的情况是一个得到服务器响应,另一个保持沉默。
您可以使用 mergeMap 而不是 switchMap(它不会取消请求),但是最好的解决方案是在调用服务函数之前使用 switchMap。
此外,将令牌制作为字符串而不是可观察的也是合理的,因为它在会话期间很少更改,您可以使用 set-get to localStorage 来确保它是最新的。
希望能帮助到你。
推荐阅读
- laravel - 如何在 Laravel 中显示限时产品报价
- mysql - MySql根据group by对查询的行进行编号
- typescript - 我可以确保其他人不会使用相同的参数调用某个函数吗?
- vbscript - ADODB.Stream 块是否与 Response.Buffer 冲突?
- javascript - 在多维 JavaScript 数组中动态保存 Smarty 值
- android - 使用 exoplayer 从 azure 媒体服务获取令牌的 Widevine 离线许可证
- java-8 - java - 如何通过在java中迭代一个没有重复的列表来过滤记录?
- r - 如何为 rstanarm 中的 stan_lmer 多级模型指定信息先验?
- git - git pull 返回警告:监听端口 52698 的远程端口转发失败
- flutter - Flutter 将 NestedScrollView 添加到 SliverChildListDelegate 并出现 RenderFlex 错误