问题
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.
the interceptor code
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))
)
}
}
and simple two requests like those
getUsers() {
return this.http.get<any[]>(`https://jsonplaceholder.typicode.com/users`);
}
getPosts() {
return this.http.get<any[]>(`https://jsonplaceholder.typicode.com/posts`);
}
And in the component
// 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);
});
I re-produced the error on example you can check it https://stackblitz.com/edit/angular-kpxvej
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);
}
回答1:
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.
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 requires both observables to be completed in order to fire, so your situation is one gets server response, the other remains silent.
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.
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.
Hope it helps.
回答2:
Try by using the following Observable configuration by adding the forkjoin
as observable
.
service.ts
getUsers(): Observable<any[]> {
return this.http.get(`https://jsonplaceholder.typicode.com/users`)
.map(res => {
return res;
});
}
getPosts(): Observable<any[]> {
return this.http.get(`https://jsonplaceholder.typicode.com/posts`);
.map(res => {
return res;
});
}
getForkJoin(): Observable<any>{
return forkJoin(
this.getUsers(),
this.getPosts()
);
}
Component.ts
this.appService.getForkJoin().subscribe(([users,posts]) =>{
console.log(users);
console.log(posts);
} );
回答3:
I solved the problem by converting the token from Observable to be just a string. and i solved the problem by doing that.
来源:https://stackoverflow.com/questions/50614121/angular-httpinterceptor-not-working-with-forkjoin