如何在Angular的Guard守卫中获取已注入的Service服务实例?
解决方案
最优方案直接使用Angular内置的**依赖注入(DI)**机制,不需要手动创建实例,也不需要设置静态方法,Angular会自动维护服务的单例实例,整个应用复用同一个实例。
步骤1:给AuthService添加注入配置
你需要先给AuthService加上@Injectable装饰器,并配置为根级注入,这样Angular启动时就会自动创建唯一的服务实例:
import { Injectable } from '@angular/core'; import { HttpClient, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { environment } from 'src/environments/environment'; @Injectable({ providedIn: 'root' // 全应用单例,无需额外在模块中声明 }) export class AuthService{ constructor(private http: HttpClient) { } getAuthStatus(): Observable<HttpResponse<any>>{ return this.http.post(environment.server + environment.routes.authRoutes.status, "", { withCredentials: true, observe: 'response' }) } }
步骤2:改造AuthGuard,注入服务并处理异步逻辑
你原来的代码有两个问题:
- 手动创建
AuthService实例无法注入HttpClient依赖,运行会报错 - 同步返回
isAuthenticated变量,http请求还没返回就已经返回了初始值false,守卫永远不会生效
Angular的CanActivate本身就支持返回Observable<boolean>/Promise<boolean>类型的异步结果,改造后代码如下:
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { AuthService } from './auth.service'; import { map, catchError } from 'rxjs/operators'; import { of, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { // 构造函数中直接注入单例的AuthService和路由服务 constructor(private auth: AuthService, private router: Router) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { return this.auth.getAuthStatus().pipe( map(res => { if(res.status === 200){ return true; } // 校验失败跳转登录页 this.router.navigate(['/login']); return false; }), catchError(() => { // 请求报错(如JWT过期、服务端错误)也跳转登录页 this.router.navigate(['/login']); return of(false); }) ); } }
原理说明
- 配置
providedIn: 'root'的服务,Angular只会在应用启动时创建一次实例,所有注入该服务的组件/守卫/其他服务都会复用同一个实例,完全满足你复用的需求 - 依赖注入框架会自动处理服务的依赖传递,比如
AuthService依赖的HttpClient会自动被注入,不需要你手动传参 - 直接返回Observable对象,路由会等待请求完成后再判断是否放行,不会出现同步返回值错误的问题
内容的提问来源于stack exchange,提问作者Kleecarim
相关产品推荐
相关产品推荐

