
本文旨在解决 Angular 应用中使用 Guard 结合多个 Observable 时,路由守卫失效的问题。通过 combineLatest 组合多个 Observable,并根据其结果决定是否允许用户访问特定路由。重点在于避免在 Observable 流中进行不必要的路由重定向,确保路由守卫的逻辑正确执行。
在 Angular 应用中,路由守卫(Guards)用于控制用户是否可以访问特定的路由。当需要根据多个条件(例如,用户角色、数据状态等)来决定是否允许访问时,通常会使用 RxJS 的操作符,如 combineLatest 或 zip,将多个 Observable 组合起来。然而,不当的使用方式可能导致路由守卫失效,例如,提前进行了不必要的路由跳转。
以下代码展示了一个常见的场景:需要判断用户是否是管理员,以及是否已经创建了 CV(简历),来决定是否允许用户访问 /new 页面。
import { Injectable } from '@angular/core';import { CanActivate, Router } from '@angular/router';import { Observable, combineLatest } from 'rxjs';import { PersonsService } from '../services/persons.service';import { map, finalize } from 'rxjs/operators';import { AdministrationService } from '../services/administration.service';import { CustomSnackbarService } from '../services/custom-snackbar.service';@Injectable({ providedIn: 'root',})export class CanCreateNewCv implements CanActivate { constructor( private usersService: PersonsService, private router: Router, private administrationService: AdministrationService, private snackbarService: CustomSnackbarService ) {} canActivate(): Observable | boolean | Promise { let isAllowed = false; const cv$ = this.usersService .getPersonsByPageAndFilter(10, 0) .pipe( map((data) => data.allDataCount > 0) ); const admin$ = this.administrationService .getCurrentUser() .pipe( map((currentUser) => currentUser.isAdmin || currentUser.isManager) ); return combineLatest([cv$, admin$], (isCvUploaded, isAdminOrManager) => { isAllowed = isAdminOrManager ? true : isCvUploaded ? false : true; if (!isAllowed) { this.router.navigateByUrl('/list'); } return isAllowed; }).pipe( finalize(() => { if (!isAllowed) this.snackbarService.open( 'This profile has CV already created!', 'Info' ); }) ); }}
问题分析:
最初的代码存在一个问题:在 cv$ Observable 的 map 操作符中,如果用户已经创建了 CV,会立即执行 this.router.navigateByUrl(‘/list’) 进行路由跳转。这会导致无论用户是否是管理员,都会被重定向到 /list 页面,从而使管理员无法访问 /new 页面。
解决方案:
正确的做法是将路由跳转的逻辑移动到 combineLatest 操作符的回调函数中。只有在 combineLatest 确定用户既不是管理员,也没有创建 CV 时,才进行路由跳转。 这样可以确保管理员始终可以访问 /new 页面,而普通用户只有在没有创建 CV 的情况下才能访问。
代码解释:
cv$ Observable: 从 PersonsService 获取用户 CV 数据,并使用 map 操作符将结果转换为一个布尔值,表示用户是否已经上传了 CV。
admin$ Observable: 从 AdministrationService 获取当前用户信息,并使用 map 操作符将结果转换为一个布尔值,表示用户是否是管理员或经理。
combineLatest([cv$, admin$], (isCvUploaded, isAdminOrManager) => { … }): 使用 combineLatest 操作符将 cv$ 和 admin$ 两个 Observable 组合起来。当两个 Observable 都发出值时,combineLatest 会调用回调函数,并将两个 Observable 的最新值作为参数传递给回调函数。
回调函数中的逻辑:
isAllowed = isAdminOrManager ? true : isCvUploaded ? false : true;:根据用户是否是管理员以及是否上传了 CV 来决定是否允许访问。如果用户是管理员,则允许访问;如果用户不是管理员,并且已经上传了 CV,则不允许访问;否则,允许访问。if (!isAllowed) { this.router.navigateByUrl(‘/list’); }:只有在不允许访问的情况下,才进行路由跳转到 /list 页面。
finalize(() => { … }): 使用 finalize 操作符在 Observable 完成时执行一些清理工作,例如显示提示信息。
总结:
在使用 RxJS 组合多个 Observable 来实现复杂的路由守卫逻辑时,需要特别注意路由跳转的时机。应该确保在所有必要的条件都满足后,再进行路由跳转,避免过早的跳转导致逻辑错误。将路由跳转的逻辑放在 combineLatest 的回调函数中是一个有效的解决方案。此外,清晰的逻辑判断和适当的注释可以提高代码的可读性和可维护性。
以上就是Angular Guard 结合多个 Observable 时失效的解决方案的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1526962.html
微信扫一扫
支付宝扫一扫