angular - 为什么 switchMap 在 Angular 拦截器(Angular 9)中不起作用
问题描述
我写了一个拦截器来为我刷新令牌。但是使用我检查的调试器,它根本没有进入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不会从头开始重复。
解决方案
您的代码应该是:-
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 不订阅您返回的内部可观察对象。合并地图就是这样做的。流组合应使用适当的运算符完成。
推荐阅读
- c# - 当前上下文中不存在“InitializeComponent”和“_FrameViews”
- html - 图像在 flexbox 中完美调整大小,直到我添加另一个元素
- azure - 有什么办法可以缓存 git 源文件?
- css - 如何在不丢失父级高度的情况下在 div 中居中项目?
- javascript - 使用 javascript 将类样式添加到 CKEditor 文本
- c++ - 解释未解决的外部 C++
- python - 如何旋转 seaborn 热图?
- reactjs - React 中的 onMouseEnter 事件有问题
- javascript - 当我保存存储的数据时,只有一个数据是另一个数据变为空。使用foreach怎么样?
- php - PHP用CSS类回显HTML导致错误?