新闻中心

Angular Guard 结合多个 Observable 时失效的解决方案

2025-10-06
浏览次数:
返回列表

angular guard 结合多个 observable 时失效的解决方案

本文旨在解决 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> | boolean | Promise<boolean> {
    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.n*igateByUrl('/list');
      }
      return isAllowed;
    }).pipe(
      finalize(() => {
        if (!isAllowed)
          this.snackbarService.open(
            'This profile has CV already created!',
            'Info'
          );
      })
    );
  }
}

问题分析:

最初的代码存在一个问题:在 cv$ Observable 的 map 操作符中,如果用户已经创建了 CV,会立即执行 this.router.n*igateByUrl('/list') 进行路由跳转。这会导致无论用户是否是管理员,都会被重定向到 /list 页面,从而使管理员无法访问 /new 页面。

解决方案:

正确的做法是将路由跳转的逻辑移动到 combineLatest 操作符的回调函数中。只有在 combineLatest 确定用户既不是管理员,也没有创建 CV 时,才进行路由跳转。 这样可以确保管理员始终可以访问 /new 页面,而普通用户只有在没有创建 CV 的情况下才能访问。

代码解释:

php商城系统(本地测试包) php商城系统(本地测试包)

PHP商城系统是国内领先商城系统,网店系统,购物系统,网上商城系统,B2C商城系统产品.同时也是一个商业的PHP开发框架。PHP 商城系统由内容、文章、会员、留言、订单、 财务、广告、短消息、数据库管理、营销推广、内置支付管理、商品配送管理、无限级分类、全站搜索等多个功能模块插件组成。在当今瞬机万变的市场环境中,快速高效的IT解决方案是您业务成功的关键。我们PHP商城系统能为您量身打造完全符合需求

php商城系统(本地测试包) 0 查看详情 php商城系统(本地测试包)
  1. cv$ Observable: 从 PersonsService 获取用户 CV 数据,并使用 map 操作符将结果转换为一个布尔值,表示用户是否已经上传了 CV。

  2. admin$ Observable: 从 AdministrationService 获取当前用户信息,并使用 map 操作符将结果转换为一个布尔值,表示用户是否是管理员或经理。

  3. combineLatest([cv$, admin$], (isCvUploaded, isAdminOrManager) => { ... }): 使用 combineLatest 操作符将 cv$ 和 admin$ 两个 Observable 组合起来。当两个 Observable 都发出值时,combineLatest 会调用回调函数,并将两个 Observable 的最新值作为参数传递给回调函数。

  4. 回调函数中的逻辑:

    • isAllowed = isAdminOrManager ? true : isCvUploaded ? false : true;:根据用户是否是管理员以及是否上传了 CV 来决定是否允许访问。如果用户是管理员,则允许访问;如果用户不是管理员,并且已经上传了 CV,则不允许访问;否则,允许访问。
    • if (!isAllowed) { this.router.n*igateByUrl('/list'); }:只有在不允许访问的情况下,才进行路由跳转到 /list 页面。
  5. finalize(() => { ... }): 使用 finalize 操作符在 Observable 完成时执行一些清理工作,例如显示提示信息。

总结:

在使用 RxJS 组合多个 Observable 来实现复杂的路由守卫逻辑时,需要特别注意路由跳转的时机。应该确保在所有必要的条件都满足后,再进行路由跳转,避免过早的跳转导致逻辑错误。将路由跳转的逻辑放在 combineLatest 的回调函数中是一个有效的解决方案。此外,清晰的逻辑判断和适当的注释可以提高代码的可读性和可维护性。

以上就是Angular Guard 结合多个 Observable 时失效的解决方案的详细内容,更多请关注其它相关文章!


# 服务端  # oa网站建设推广  # 小程序推广 素材网站  # 鄂州全网营销推广机构  # 黄冈品牌seo推广  # 渤海新区网络营销推广  # 网站推广有哪些方式好呢  # 农夫山泉营销推广方案PPT  # 餐饮网站建设最好  # 长春彩妆小红书推广营销  # 养老网站建设总结怎么写  # 重定向  # 如何实现  # js  # 如何使用  # 转换为  # 传了  # 回调  # 跳转  # 多个  # 营销推广  # gate  # 简历  # 路由  # 回调函数 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: 微博网页版怎么开启两步验证_微博网页版账号安全两步验证设置方法  在WordPress中通过REST API获取BasicAuth保护的远程文章  C#如何安全地从用户上传的XML文件中读取数据? 验证与清理策略  Win10怎么制作U盘启动盘 Win10系统安装U盘制作教程【详解】  LINUX下如何进行磁盘分区_fdisk与parted工具在LINUX中的使用对比  内存疯狂猛猛涨价:主板销量直接腰斩!  怎么在mac上运行html代码_mac运行html代码方法【指南】  LINUX的I/O重定向是什么_深入理解LINUX中 >、>> 与 < 的区别  如何在Promise链中优雅地中断后续then执行  UC浏览器如何安装插件 UC浏览器添加扩展程序详细教程【进阶】  谷歌浏览器无痕模式怎么开 Chrome开启无痕浏览设置方法【教程】  4399免费游戏网址入口 4399小游戏免费入口点开即玩  HTML长属性值处理:表单action路径优化与代码规范应对  C++ explicit关键字防止隐式转换_C++构造函数安全规范  手机CPU怎么影响游戏体验_手机CPU对游戏性能的影响分析  如何将一个大型PHP应用拆分为多个Composer包_微服务与模块化架构的Composer实践  php源码怎么看淘宝客系统_看php源码淘宝客系统技巧  提升屏幕阅读器对“m”时间单位的播报准确性:HTML与CSS组合解决方案  wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法  sublime如何优雅地处理行尾空格_sublime自动清理多余空白字符配置  腾讯QQ邮箱登录入口_QQ邮箱官方网站使用地址  J*aScript中向JSON对象添加新属性的正确姿势  Pygame教程:解决用户输入与游戏状态更新不同步问题  最新韩小圈网页版登录入口_官网在线观看官方链接  J*a里如何实现订单支付与库存同步功能_支付库存同步项目开发方法说明  Go Martini框架:动态服务解码后的图片内容  小米Civi 4录制视频过暗_小米Civi 4亮度优化  绝地鸭卫平a核爆刀流玩法攻略  126邮箱网页版官方入口 126邮箱账号在线登录平台  iCloud登录入口网页版 苹果iCloud官网登录  ArchiveofOurOwn小说阅读-ArchiveofOurOwn同人作品访问链接  Golang如何实现状态模式管理对象状态_Golang State模式实现技巧  Go语言中的*string:深入理解字符串指针  uc浏览器网页版极速入口 uc网页浏览器网页版流畅体验  sublime侧边栏怎么增强功能_SideBarEnhancements for sublime安装与配置  KFC早餐时段怎么领特惠代码_KFC早餐订餐优惠代码获取与使用说明  优化 Python 函数中的条件逻辑:解决 if-else 嵌套与参数选择问题  CSS子选择器:如何区分并样式化嵌套列表的子层级  CSS Flexbox与媒体查询:实现响应式布局中元素的并排与堆叠  深入理解Go语言中的指针类型:以*string为例  Excel Power Pivot如何处理XML数据源 构建高级数据模型  iwriter统一登录平台 iwrite账号密码登录页面  一加手机拍照效果不好怎么办 一加哈苏影像调校与专业模式使用教程【高手篇】  CKEditor 5 自定义构建在React应用中渲染失败的调试与解决  格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施  c++如何使用Catch2编写单元测试_c++简洁易用的BDD风格测试框架  composer 和 npm/yarn 在管理依赖方面有什么核心思想差异?  Go语言HTML解析:利用Goquery精准获取指定元素内容  在Qt QML中通过Python字典动态更新TextEdit内容的教程  Composer的 "conflict" 字段有什么用_如何声明不兼容的包以避免依赖冲突 

搜索