Angular类守卫转函数式守卫时inject()无法获取实例求助
问题:Angular函数式守卫中inject无法获取SSR_MANAGER实例
原基于类的守卫实现
import { isPlatformServer } from '@angular/common'; import { Inject, Injectable, Optional, PLATFORM_ID } from '@angular/core'; @Injectable() export class Session2Guard implements CanActivate { constructor( @Inject(PLATFORM_ID) private platfirmId: Object, @Inject('SSR_MANAGER') @Optional() private ssrManager?: SsrManager ) {} canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> { if (isPlatformServer(this.platfirmId)) { this.ssrManager.preventSsr(); } } }
修改后的函数式守卫实现
import { inject, InjectionToken, PLATFORM_ID } from '@angular/core'; import { isPlatformServer } from '@angular/common'; import { CanActivateFn } from '@angular/router'; import { Observable, of } from 'rxjs'; export const SessionGuard: CanActivateFn = (): Observable<boolean> => { const platformId: Object = inject(PLATFORM_ID); const ssrManager: SsrManager = inject(new InjectionToken('SSR_MANAGER'), { optional: true, }); if (isPlatformServer(platformId)) { return of(true); } };
问题现象
将类守卫改为函数式守卫后,inject()始终无法获取到SSR_MANAGER的实例,返回值一直为null。
解决方案
问题核心在于DI令牌不匹配:
- 原类守卫使用的是字符串令牌
'SSR_MANAGER',而函数式守卫中每次调用inject时都新建了一个InjectionToken实例。Angular的DI系统是通过令牌的引用(而非名称字符串)来匹配依赖的,两者不属于同一令牌,因此无法找到对应实例。
调整方案二选一:
直接复用字符串令牌
如果项目中是通过字符串令牌注册的SSR_MANAGER,直接传入字符串即可:const ssrManager: SsrManager = inject('SSR_MANAGER', { optional: true });导入项目中已定义的InjectionToken常量(推荐)
如果项目中原本就定义了对应的令牌常量,直接导入使用:// 假设项目中已在某个文件定义该令牌 export const SSR_MANAGER = new InjectionToken<SsrManager>('SSR_MANAGER'); // 在函数式守卫中导入并使用 import { SSR_MANAGER } from './path-to-token-file'; const ssrManager: SsrManager = inject(SSR_MANAGER, { optional: true });
额外补全逻辑
原类守卫中服务端环境调用ssrManager.preventSsr()的逻辑在函数式守卫中被遗漏,记得补全(同时用可选链避免null报错):
if (isPlatformServer(platformId)) { ssrManager?.preventSsr(); return of(true); } // 补充客户端环境的返回逻辑,原代码也存在遗漏,需根据实际业务调整 return of(true);
内容的提问来源于stack exchange,提问作者Nerses Nersesyan
相关产品推荐
相关产品推荐

