Angular 7 RXJS Observables timer interval infinite loop start immediately
我正在尝试使这些RXJS可观对象在Angular 7中正常工作,但我不知道出了什么问题。
我想做的是检查每10秒是否有用于验证的验证令牌状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import {Injectable} from '@angular/core'; import {HttpClient, HttpHeaders} from '@angular/common/http'; import {interval, Observable, of, timer} from 'rxjs'; import {concatMap, delay, flatMap, takeWhile, tap} from 'rxjs/operators'; import {Token} from './Token'; import {User} from './User'; import {TokenFactory} from './factory/tokenfactory'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; @Injectable({ providedIn: 'root' }) export class TokenService { private user; private token; private tokenLoginUrl = 'http://localhost:8080/login_check'; private refreshTokenUrl = 'http://localhost:8080/token/refresh'; constructor(private http: HttpClient) { } private verifyTokenState(): Observable { if (!localStorage.getItem('token')) { this.getLoginInfo().subscribe(token => { this.token = TokenFactory.createToken(token.token, token.refresh_token, Date.now(), true); return of(this.token); }); this.token = {}; return of(this.token); } this.token = TokenFactory.getTokenFromLocalStorage(); const timeElapsedInMinutes = (Date.now() - this.token.date_token) / 1000 / 60; console.log(timeElapsedInMinutes); if (timeElapsedInMinutes >= 59) { this.getRefreshToken(this.token).subscribe(jsonToken => { this.token = TokenFactory.createToken(jsonToken.token, jsonToken.refresh_token, Date.now(), true); return of(this.token); }); } return of(this.token); } private getLoginInfo(): Observable { return this.http.post<Token>(this.tokenLoginUrl, this.user, httpOptions); } private getRefreshToken(token: Token): Observable { return this.http.post<Token>(this.refreshTokenUrl, token, httpOptions); } public getToken() { return timer(0, 10000).pipe( flatMap(() => this.verifyTokenState()), takeWhile(() => this.token !== undefined && !this.token.isValid) ); } public setUser(user: User): void { this.user = user; } } |
我遇到的问题是,当我从另一个组件内部调用get TokenService.getToken()时(假设用户单击提交按钮后在登录组件中),并且我使用
getRefreshToken()方法在无限循环中被调用,并且触发了数百个ajax调用。
1 2 3 4 5 6 | public getToken() { return timer(0, 10000).pipe( flatMap(() => this.verifyTokenState()), takeWhile(() => this.token !== undefined && !this.token.isValid) ); } |
我不明白的是,如果我使用2000而不是0作为第一个参数,则一切正常,但这不是我想要的。
1 2 3 4 5 6 | public getToken() { return timer(2000, 10000).pipe( flatMap(() => this.verifyTokenState()), takeWhile(() => this.token !== undefined && !this.token.isValid) ); } |
我确切想要的是观察到的呼叫之间有10秒的间隔,但我希望它立即开始。我还想获得从verifyTokenSate()方法返回的getToken()返回的可观察令牌。那么到底是怎么了?有更好的方法吗?我想以被动方式进行此操作,而无需取消订阅。
经过进一步调查后,该问题似乎在AuthInterceptor中发生。当我从模块提供程序中删除时,一切正常。这是AuthInterceptor:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | import {Injectable} from '@angular/core'; import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; import {TokenService} from './token.service'; import {Observable} from 'rxjs'; import {map, mergeMap} from 'rxjs/operators'; @Injectable() export class AuthInterceptor implements HttpInterceptor { private token; constructor(private auth: TokenService) { } intercept( req: HttpRequest, next: HttpHandler ): Observable<HttpEvent> { let request = req.clone(); this.auth.getToken().subscribe(t => { console.log(t); if (t.token) { console.log('token valid'); request = req.clone({ setHeaders: { Authorization: `Bearer ${t.token}` } }); } }); return next.handle(request); } } |
那么AuthInterceptor内部有什么问题?
AuthInterceptor可能会拦截http登录/刷新URL的请求,进而本身(通过this.auth.getToken())触发这些调用,从而导致循环性。 一种可能的解决方案是不拦截(或跳过)这些http请求
1 2 3 4 5 6 7 8 9 10 11 12 | intercept( req: HttpRequest, next: HttpHandler ): Observable<HttpEvent> { // whitelisting certain urls that don't need token check if (req.url.includes('/login_check') || req.url.includes('/token/refresh')) { return next.handle(req); } // remaining code } |