Angular路由守卫中pipe()返回undefined,subscribe()可用却报错
我正在使用PEAN栈(PostgreSQL - ExpressJS - Angular - NodeJS)开发一款认证应用。
问题
我的路由守卫(auth guard)存在如下问题:
- 使用
subscribe()时,控制台能输出预期结果。✔ 可用 - 使用
pipe()时,控制台输出undefined。✖ 不可用
if-signed-in.guard.ts
import { CanActivateFn } from '@angular/router'; import { AuthService } from '../services/auth/auth.service'; import { inject } from '@angular/core'; import { tap, map } from 'rxjs/operators'; import { Router } from '@angular/router'; export const IfSignedIn: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); auth.getSignInStatusObserver().subscribe((res: any) => { console.log(res); }); return auth.getSignInStatusObserver().pipe( tap((status) => { console.log(status); }), map((status) => { console.log(status); if (status) { if (status.success === true) { return true; } else { router.navigate(['/dashboard']); return false; } } else { router.navigate(['/dashboard']); return false; } }) ); };
控制台截图:
已尝试方案
我尝试将逻辑移入subscribe()中,修改后的代码如下:
import { CanActivateFn } from '@angular/router'; import { AuthService } from '../services/auth/auth.service'; import { inject } from '@angular/core'; import { Router } from '@angular/router'; export const IfSignedIn: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); auth.getSignInStatusObserver().subscribe((res: any) => { if (res) { if (res.success === true) { return true; } else { router.navigate(['/dashboard']); return false; } } else { router.navigate(['/dashboard']); return false; } }); };
但出现如下编译错误:
src/app/auth/guards/if-signed-in.guard.ts:7:14 - error TS2322: Type
'(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => void'
is not assignable to type 'CanActivateFn'. Type 'void' is not
assignable to type 'boolean | UrlTree | Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>'.7 export const IfSignedIn: CanActivateFn = (route, state) => {
核心问题
为什么在路由守卫中使用pipe()时Observable返回undefined,而subscribe()能得到结果却报错?
编辑1
我尝试了@MatthieuRiegler建议的代码,添加了filter操作符过滤undefined值,但仍得到和之前一样的结果。修改后的代码:
import { CanActivateFn } from '@angular/router'; import { AuthService } from '../services/auth/auth.service'; import { inject } from '@angular/core'; import { filter, tap, map } from 'rxjs/operators'; import { Router } from '@angular/router'; export const IfSignedIn: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); auth.getSignInStatusObserver().subscribe((res: any) => { console.log(res); }); return auth.getSignInStatusObserver().pipe( filter((status) => status !== undefined), tap((status) => { console.log(status); }), map((status) => { console.log(status); if (status) { if (status.success === true) { return true; } else { router.navigate(['/dashboard']); return false; } } else { router.navigate(['/dashboard']); return false; } }) ); };
编辑2
应用表现异常,当前代码如下:
import { CanActivateFn } from '@angular/router'; import { AuthService } from '../services/auth/auth.service'; import { inject } from '@angular/core'; import { filter, tap, map } from 'rxjs/operators'; import { Router } from '@angular/router'; export const IfSignedIn: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); return auth.getSignInStatusObserver().pipe( filter((status) => status !== undefined), tap((status) => { console.log('Tap: ', status); }), map((status) => { console.log('Map: ', status); if (status) { if (status.success === true) { return true; } else { router.navigate(['/dashboard']); return false; } } else { router.navigate(['/dashboard']); return false; } }) ); };
点击“编辑资料”按钮时一切正常,但直接在地址栏输入http://localhost:4200/profile/edit-profile或刷新页面时,会收到undefined,且因filter()生效,控制台无输出,路由守卫在页面刷新时失效。
操作演示截图:
编辑3
我使用拦截器设置登录状态,相关代码如下:
sign-in-status.service.ts
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; import { tap, catchError } from 'rxjs/operators'; import { AuthService } from 'src/app/auth/services/auth/auth.service'; @Injectable({ providedIn: 'root', }) export class SignInStatusService implements HttpInterceptor { intercept(httpRequest: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { return next.handle(httpRequest).pipe( tap((event: HttpEvent<any>) => { if (event instanceof HttpResponse && httpRequest.url.endsWith('api/get-user') && event.status === 200) { this.authService.setSignInStatus({ success: true, response: event.body }); } }), catchError((err: any) => { if (httpRequest.url.endsWith('api/get-user')) { this.authService.setSignInStatus({ success: false, response: err }); } return throwError(() => err); }) ); } constructor(private authService: AuthService) {} }
内容的提问来源于stack exchange,提问作者Rok Benko

