angular - Angular 7 RXJS Observables 计时器间隔无限循环立即开始
问题描述
我正在尝试使这些 RXJS 可观察对象与 Angular 7 一起正常工作,但我不知道出了什么问题。
我想要做的是检查是否每 10 秒验证一次令牌状态以进行身份验证。
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<any> {
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<any> {
return this.http.post<Token>(this.tokenLoginUrl, this.user, httpOptions);
}
private getRefreshToken(token: Token): Observable<any> {
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() 时(假设在用户单击提交按钮后的登录组件中)并且我使用timer(0,10000)
getLoginInfo() 和 getRefreshToken() 方法被调用无限循环,并且触发了数百个 ajax 调用。
public getToken() {
return timer(0, 10000).pipe(
flatMap(() => this.verifyTokenState()),
takeWhile(() => this.token !== undefined && !this.token.isValid)
);
}
我不明白的是,如果我使用 2000 而不是 0 作为第一个参数,一切正常,但这不是我想要的。
public getToken() {
return timer(2000, 10000).pipe(
flatMap(() => this.verifyTokenState()),
takeWhile(() => this.token !== undefined && !this.token.isValid)
);
}
我想要的是让 observable 在调用之间有 10 秒的间隔,但我希望它立即开始。在从 verifyTokenSate() 方法返回后,我还想从 getToken() 返回一个可观察的 Token。那么究竟有什么问题呢?有更好的方法吗?我想在不取消订阅的情况下以被动的方式做到这一点。
在进一步调查后,这些问题似乎发生在 AuthInterceptor 中。当我从模块提供程序中删除时,一切正常。这是 AuthInterceptor:
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<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
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 可能会拦截登录/刷新 url 的 http 请求,进而触发这些调用本身(通过 this.auth.getToken()),从而导致循环性质。一个可能的解决方案是不拦截(或跳过)这些 http 请求
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
// 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
}
推荐阅读
- laravel-5 - php vendor/bin/phpunit 空结果 Laravel 5
- python - 如何在 Micropython 中编写一个可以用参数初始化的类?
- angularjs - 即使没有使用 DI,ng-strict-di 也会抛出错误
- html - 导航栏上的Bootstrap 4粘顶类不起作用
- go - golang 最新稳定版本的 URL
- android - com.google.android.gms.internal.firebase-perf.zzw 上的 NoClassDefFoundError
- python-3.x - 从其他文件加载功能时训练的目的?
- javascript - Node.js:在同一台服务器上运行多个应用程序
- javascript - 如何获取拥有多个孩子的元素?
- windows - FFMPEG - 如何准确获取文件名并在渲染队列的每个输出视频中添加绘图文本