为啥 switchMap 在 Angular 拦截器(Angular 9)中不起作用
Posted
技术标签:
【中文标题】为啥 switchMap 在 Angular 拦截器(Angular 9)中不起作用【英文标题】:why switchMap not working in Angular interceptor ( Angular 9 )为什么 switchMap 在 Angular 拦截器(Angular 9)中不起作用 【发布时间】:2020-09-18 19:54:29 【问题描述】:我写了一个拦截器来为我刷新令牌。但是使用我检查的调试器,它根本没有进入 switchMap ,并且请求不会再次发送它。 有谁知道问题出在哪里?
import HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse from '@angular/common/http';
import Injectable, Injector from '@angular/core';
import BehaviorSubject, Observable from 'rxjs';
import catchError, switchMap, tap from 'rxjs/operators';
import ResponseModel from '../Models/responseModel';
import UserDataModel from '../Models/UserDataModel';
import RoleEnum from '../Enums/RoleEnum';
import AuthService from '../../auth/auth.service';
import AuthModel from '../Models/authModel';
import LoginType from '../Enums/LoginType';
import LoginResponseModel from '../Models/LoginResponseModel';
@Injectable(providedIn: 'root')
export class TokenInterceptor implements HttpInterceptor
httpSubject: BehaviorSubject<LoginResponseModel> = new BehaviorSubject<LoginResponseModel>(null);
constructor(private injector: Injector)
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
let modifiedReq;
const userData:
username: string,
access_token: string,
refresh_token: string,
role: RoleEnum,
_tokenexpirationDate: string
= (JSON.parse(localStorage.getItem('userData')));
if (userData.access_token !== null && !req.headers.has('X-Skip-Interceptor'))
modifiedReq = req.clone(
headers: req.headers.set('access_token', `$userData.access_token`),
);
else
modifiedReq = req.clone(
setHeaders:
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
);
return next.handle(modifiedReq).pipe(tap(res =>
if (res instanceof HttpResponse)
const response = (<HttpResponse<ResponseModel<string>>> res).body;
/*const userdata:
username: string,
access_token: string,
refresh_token: string,
role: RoleEnum,
_tokenexpirationDate: string
= (JSON.parse(localStorage.getItem('userData')));*/
if (!response.is_successfull)
if (new Date() > new Date(userData._tokenexpirationDate))
this.refreshToken(req, next, userData.refresh_token, userData.username);
));
refreshToken(req: HttpRequest<any>, next: HttpHandler, refreshtoken: string, username: string)
this.httpSubject.next(null);
const authService = this.injector.get(AuthService);
const authmodel: AuthModel =
email_address: '', grant_type: LoginType.RefreshToken, password: '', phone_number: '', phone_number_countery_iso2_code: '',
refresh_token: refreshtoken, username: ''
;
debugger;
return authService.Signin(authmodel).pipe(
switchMap(result =>
debugger;
if (result.is_successfull && result.response.access_token !== null)
const expirationDate = new Date(new Date().getTime() + +result.response.expires_in * 60000);
const user = new UserDataModel(username, result.response.access_token, result.response.refresh_token
, result.response.role, expirationDate);
localStorage.setItem('userData', JSON.stringify(user));
this.httpSubject.next(result.response);
req = req.clone(
setHeaders:
access_token: `$result.response.access_token`
);
return next.handle(req);
) , catchError(err =>
console.log(err);
return Observable;
));
我还要说,如果我用subscribe代替pipe,switchMap,token会被刷新,只有request不会从头开始重复。
【问题讨论】:
@AakashGarg 您无需评论您已发布答案。 OP 在他们的收件箱中收到警报。无需惹恼任何人。 【参考方案1】:你的代码应该是:-
import HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse from '@angular/common/http';
import Injectable, Injector from '@angular/core';
import BehaviorSubject, Observable from 'rxjs';
import catchError, switchMap, tap from 'rxjs/operators';
import ResponseModel from '../Models/responseModel';
import UserDataModel from '../Models/UserDataModel';
import RoleEnum from '../Enums/RoleEnum';
import AuthService from '../../auth/auth.service';
import AuthModel from '../Models/authModel';
import LoginType from '../Enums/LoginType';
import LoginResponseModel from '../Models/LoginResponseModel';
@Injectable(providedIn: 'root')
export class TokenInterceptor implements HttpInterceptor
httpSubject: BehaviorSubject<LoginResponseModel> = new BehaviorSubject<LoginResponseModel>(null);
constructor(private injector: Injector)
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
let modifiedReq;
const userData:
username: string,
access_token: string,
refresh_token: string,
role: RoleEnum,
_tokenexpirationDate: string
= (JSON.parse(localStorage.getItem('userData')));
if (userData.access_token !== null && !req.headers.has('X-Skip-Interceptor'))
modifiedReq = req.clone(
headers: req.headers.set('access_token', `$userData.access_token`),
);
else
modifiedReq = req.clone(
setHeaders:
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
);
return next.handle(modifiedReq).pipe(tap(res =>
if (res instanceof HttpResponse)
const response = (<HttpResponse<ResponseModel<string>>> res).body;
/*const userdata:
username: string,
access_token: string,
refresh_token: string,
role: RoleEnum,
_tokenexpirationDate: string
= (JSON.parse(localStorage.getItem('userData')));*/
if (!response.is_successfull)
if (new Date() > new Date(userData._tokenexpirationDate))
this.refreshToken(req, next, userData.refresh_token, userData.username).then((request)=>
modifiedRequest = request.clone();
throw "replay";
);
),retryWhen(errors => errors);
refreshToken(req: HttpRequest<any>, next: HttpHandler, refreshtoken: string, username: string)
this.httpSubject.next(null);
const authService = this.injector.get(AuthService);
const authmodel: AuthModel =
email_address: '', grant_type: LoginType.RefreshToken, password: '', phone_number: '', phone_number_countery_iso2_code: '',
refresh_token: refreshtoken, username: ''
;
debugger;
return await authService.Signin(authmodel).pipe(
map(result =>
debugger;
if (result.is_successfull && result.response.access_token !== null)
const expirationDate = new Date(new Date().getTime() + +result.response.expires_in * 60000);
const user = new UserDataModel(username, result.response.access_token, result.response.refresh_token
, result.response.role, expirationDate);
localStorage.setItem('userData', JSON.stringify(user));
this.httpSubject.next(result.response);
req = req.clone(
setHeaders:
access_token: `$result.response.access_token`
);
return req;
) , catchError(err =>
console.log(err);
return Observable;
)).toPromise();
原因:- Tap 没有订阅您返回的内部 observable。合并地图就是这样做的。流组合应使用适当的运算符。
【讨论】:
mergeMap 将标记添加到其顶部的标头会毁了我。难道没有别的办法了吗?还是其他运营商?我只想访问响应并能够理解我需要刷新令牌。然后重复请求。 是的,我试过了。但是一些问题,例如向标头添加令牌,被打乱了。没有别的办法吗? 我添加了没有合并映射的新代码你试过了吗? 我现在测试了它。就好像我说如果我订阅就会发生。它进入了Switchmap,刷新了token,但是没有重复之前的请求。如果我再次手动重复,那很好,因为我们有一个新令牌,但我希望这自动发生。我读到 switchMap 可以为我做到这一点。 对不起,我正在纠正。请求再次完成。但答案并不在我问的地方。我在哪里订阅我的服务。以上是关于为啥 switchMap 在 Angular 拦截器(Angular 9)中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Angular 中使用 Jasmine 测试 RxJS switchMap?
来自 Angular Redux Store 的 SwitchMap 结果
在Angular App中的Obseable POST请求中使用switchMap
使用 switchmap 和 forkjoin 链接 observables 不能按预期工作 angular typescript rxjs