Rxjs/Angular 4- 如果我在地址栏上输入 AuthGuarded URL,在 Auth 状态检查中使用 publishReplay() 会使我的应用程序无响应
Rxjs/Angular 4- using publishReplay() on Auth status checking makes my app unresponsive if I enter an AuthGuarded URL on the address bar
首先,我的没有 publishReplay() 的应用程序现在工作正常,但我想通过使用某种缓存来优化请求,以避免每次都去后端检查用户是否登录。我有以下上下文。我有需要根据是否登录的用户隐藏或显示的身份验证感知组件。我有
a) 一个 AuthGuard 来保护某些路由,如果用户未登录,它会将用户重定向到登录路由:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router){}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated().map(isAuth => {
console.log('is authenticated',isAuth);
if (isAuth) {
return true;
}else{
this.router.navigate(['/signin']);
return false;
}
});
}
}
b) 使用方法 isAuthenticated 的 AuthService 以检查用户是否已登录(我正在使用存储在数据库中的常规会话)。在链的末尾,我使用的是 publishReplay(3),因为我有 3 个组件在加载时可以识别身份验证。请注意,如果我删除该方法,一切正常并且 authguard 完成其工作,如果我添加它然后我转到示例 localhost:4200/dashboard 并且应用程序冻结,链接不起作用并且 auth guard 代码是没有得到执行,因为我在 AuthGuard 上放置了一个 console.log 'is authenticated' (如上所示)并且它没有显示在控制台上,给人的想法是执行永远不会到达那里。如果我删除 publishReplay,那么我会在控制台上再次看到消息:
isAuthenticated():可观察{
let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
return this.http.get('http://localhost:3000/api/addsfiliates/sponsor/check/login',options)
.map(response => {
let res = response.json();
console.log("response");
if (res.code == 200) {
this.userIsAuthenticated.next(true);
return true;
}
}
).catch((err)=>{
//maybe add in the future if the code is 403 then send him to login otherwise send him elsewhere
return Observable.of(false);
}).publishReplay(3);
}
c)保护路由的路由文件,仅作上下文解释:
const appRoutes: Routes = [
{ path: '', redirectTo: '/', pathMatch:'full'},
{ path: '', component: MainComponent },
{ path: 'signin', component:SigninComponent},
{ path: 'signup', component: SignupComponent},
{ path: 'dashboard', canActivate:[AuthGuard],component: DashboardComponent,
children: [
{ path: '', redirectTo:'dashboard/overview', pathMatch: 'full'},
{ path: 'overview', component: OverviewCampaignsComponent },
{ path: 'active', component: ActiveCampaignsComponent},
{ path: 'history', component: HistoryCampaignsComponent}
] }
]
我是否采用了正确的方法来对授权感知组件进行缓存?如果是,我如何使用此发布重放方法使其适用于我的用例?非常感谢
publishReplay
returns ConnectableObservable
你需要调用 connect
然后它会连接到源 observable:
let obs = this.http.get(...)
.publishReplay(1);
obs.connect;
return obs;
这应该可以修复您的应用,但您无法完成您想要的。因为在每次调用时,您仍然会创建一个新的可观察对象,从而调用服务器。
最简单直接的解决方案是:
export class AuthService {
private isAuthenticatedValue: boolean;
isAuthenticated(): Observable<boolean> {
if(this.isAuthenticatedValue != null) {
return Observable.of(this.isAuthenticatedValue);
}
return this.http.get(...)
...
.do(flag => {
this.isAuthenticatedValue = flag;
})
}
}
此外,您应该定期清除缓存值,因为会话可能会在服务器上过期。您可以通过使用 setTimeout
.
清除值来实现
首先,我的没有 publishReplay() 的应用程序现在工作正常,但我想通过使用某种缓存来优化请求,以避免每次都去后端检查用户是否登录。我有以下上下文。我有需要根据是否登录的用户隐藏或显示的身份验证感知组件。我有
a) 一个 AuthGuard 来保护某些路由,如果用户未登录,它会将用户重定向到登录路由:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router){}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated().map(isAuth => {
console.log('is authenticated',isAuth);
if (isAuth) {
return true;
}else{
this.router.navigate(['/signin']);
return false;
}
});
}
}
b) 使用方法 isAuthenticated 的 AuthService 以检查用户是否已登录(我正在使用存储在数据库中的常规会话)。在链的末尾,我使用的是 publishReplay(3),因为我有 3 个组件在加载时可以识别身份验证。请注意,如果我删除该方法,一切正常并且 authguard 完成其工作,如果我添加它然后我转到示例 localhost:4200/dashboard 并且应用程序冻结,链接不起作用并且 auth guard 代码是没有得到执行,因为我在 AuthGuard 上放置了一个 console.log 'is authenticated' (如上所示)并且它没有显示在控制台上,给人的想法是执行永远不会到达那里。如果我删除 publishReplay,那么我会在控制台上再次看到消息:
isAuthenticated():可观察{
let options = new RequestOptions({ headers: this.getHeaders(), withCredentials: true });
return this.http.get('http://localhost:3000/api/addsfiliates/sponsor/check/login',options)
.map(response => {
let res = response.json();
console.log("response");
if (res.code == 200) {
this.userIsAuthenticated.next(true);
return true;
}
}
).catch((err)=>{
//maybe add in the future if the code is 403 then send him to login otherwise send him elsewhere
return Observable.of(false);
}).publishReplay(3);
}
c)保护路由的路由文件,仅作上下文解释:
const appRoutes: Routes = [
{ path: '', redirectTo: '/', pathMatch:'full'},
{ path: '', component: MainComponent },
{ path: 'signin', component:SigninComponent},
{ path: 'signup', component: SignupComponent},
{ path: 'dashboard', canActivate:[AuthGuard],component: DashboardComponent,
children: [
{ path: '', redirectTo:'dashboard/overview', pathMatch: 'full'},
{ path: 'overview', component: OverviewCampaignsComponent },
{ path: 'active', component: ActiveCampaignsComponent},
{ path: 'history', component: HistoryCampaignsComponent}
] }
]
我是否采用了正确的方法来对授权感知组件进行缓存?如果是,我如何使用此发布重放方法使其适用于我的用例?非常感谢
publishReplay
returns ConnectableObservable
你需要调用 connect
然后它会连接到源 observable:
let obs = this.http.get(...)
.publishReplay(1);
obs.connect;
return obs;
这应该可以修复您的应用,但您无法完成您想要的。因为在每次调用时,您仍然会创建一个新的可观察对象,从而调用服务器。
最简单直接的解决方案是:
export class AuthService {
private isAuthenticatedValue: boolean;
isAuthenticated(): Observable<boolean> {
if(this.isAuthenticatedValue != null) {
return Observable.of(this.isAuthenticatedValue);
}
return this.http.get(...)
...
.do(flag => {
this.isAuthenticatedValue = flag;
})
}
}
此外,您应该定期清除缓存值,因为会话可能会在服务器上过期。您可以通过使用 setTimeout
.