我让Service从类型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);
});
我在example中重现了这个错误,你可以在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);
}
发布于 2018-08-22 08:12:34
据我所知,在拦截器中,如果您使用token作为Observable和switchMap,您可能会以一个请求取消另一个请求而结束。
您的特定示例将变成:(getUsers触发->拦截添加令牌& getPosts触发->拦截添加令牌) -> switchMap (取消上一个被拦截的请求) ->仅实际触发1个请求。
forkJoin需要完成两个可观察对象才能触发,所以您的情况是一个获得服务器响应,另一个保持沉默。
您可以使用mergeMap而不是switchMap (这不会取消请求),但是最好的解决方案是在调用服务函数之前使用switchMap。
此外,合理的做法是将令牌设置为字符串,而不是可观察的,因为它在会话期间很少更改,您可以使用localStorage的set-get来确保它是最新的。
希望能有所帮助。
发布于 2021-09-25 16:46:24
这可能有点晚了,但除了Ngoc Nam Nguyen anwser (这很有帮助)之外。对我来说,这有助于在接收器中切换到mergeMap,并使用take one来确保任何令牌更改不会在以后影响拦截器。所以我最终得到了一个像这样的拦截器:
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);
})
);
}
因此,我能够将该标记保留为可观察性,我认为这会更好一些。
发布于 2018-08-22 00:53:38
我通过将令牌从Observable转换为字符串解决了这个问题。我通过这样做解决了这个问题。
https://stackoverflow.com/questions/50614121
复制相似问题