为什么 switchMap 在 Angular 拦截器(Angular 9)中不起作用
why switchMap not working in Angular interceptor ( 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 没有订阅您返回的内部可观察对象。 mergemap 就是这样做的。应使用适当的运算符进行流组合。
我写了一个拦截器来为我刷新令牌。但是用我查的调试器,根本就没有进入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 没有订阅您返回的内部可观察对象。 mergemap 就是这样做的。应使用适当的运算符进行流组合。