问题描述
我有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 ithttps://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 worklike 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一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!