Angular中Observable错误处理:AuthGuard 401异常拦截问题
AuthGuard未处理401错误导致无法跳转登录页
问题描述
创建AuthGuard时,期望未登录用户访问受保护路由时自动跳转到登录页,但实际出现错误且无任何跳转。后端在未检测到Auth Token时返回:
{"status":401,"message":"Auth Token Not found!"}
现有代码
AuthGuardService
export class AuthGuardService implements CanActivate { constructor(private authService: AuthService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean> { return this.authService.checkLogin().pipe( map((data: HttpResponse) => { if (data.status == 200) { console.log("OUTPUT:", data) return true } else return false }), ) } }
AuthService的checkLogin方法
public checkLogin():Observable<HttpResponse> { return this.http.get<HttpResponse>('http://localhost:5000/auth/check-login', { withCredentials: true }) }
问题分析
- HttpClient默认行为:Angular的HttpClient会将非2xx状态码的响应视为错误,直接进入错误流,不会执行
map操作符中的逻辑,因此原代码无法处理401错误。 - 未获取完整HTTP响应:原
get请求未设置observe: 'response'选项,返回的是响应体数据而非HttpResponse对象,导致data.status无法正确获取。
解决方案
步骤1:修改AuthService,获取完整HTTP响应
在get请求中添加observe: 'response'选项,确保能拿到包含状态码的HttpResponse对象:
import { HttpClient, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; public checkLogin(): Observable<HttpResponse<any>> { return this.http.get<any>( 'http://localhost:5000/auth/check-login', { withCredentials: true, observe: 'response' // 关键:获取完整的HTTP响应 } ); }
步骤2:修改AuthGuard,处理错误并跳转登录页
使用catchError操作符捕获HTTP错误,跳转至登录页并返回false以阻止路由访问,同时可保存当前路由地址以便登录后跳转:
import { map, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; export class AuthGuardService implements CanActivate { constructor(private authService: AuthService, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { return this.authService.checkLogin().pipe( map((data: HttpResponse<any>) => { // 仅在200状态码时允许访问 if (data.status === 200) { console.log("OUTPUT:", data); return true; } // 非200状态码(理论上不会走到这里,因为HttpClient会抛错) this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; }), catchError(() => { // 捕获401等所有HTTP错误,跳转登录页 this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return of(false); }) ); } }
关键说明
catchError会捕获所有HTTP错误(包括401),确保无论后端返回什么错误状态码,都能触发登录跳转。queryParams: { returnUrl: state.url }保存当前用户试图访问的路由,登录成功后可跳回该页面,提升用户体验。- 修正了类型定义,使用
HttpResponse<any>明确响应类型,避免类型错误。
内容的提问来源于stack exchange,提问作者Snake_Eyes
相关产品推荐
相关产品推荐

