ngx-cookie-service页面刷新失效,添加catchError后报错求助
问题场景
- Angular项目通过
ngx-cookie-service存储登录态,登录成功后设置employeeIdCookie - 页面刷新时,浏览器控制台能正常打印
employeeId,但Angular终端显示该值为空,直接导致接口请求报错 - 首次登录后功能正常,仅刷新页面时触发此问题;且接口调用未添加
catchError时错误被静默忽略,看起来“正常”,添加错误处理后则显露出报错
相关代码片段
登录组件设置Cookie代码
login() { this.loading = true; this.loginServie.login(this.model) .pipe( catchError(error => { this.loading = false; console.error('Login failed:', error); return throwError(() => error); }) ) .subscribe( response => { this.loading = false; this.cookieService.set('employeeId', response.employeeId); this.router.navigate(['dashboard']); } ); }
DashboardService获取Cookie并发起接口请求代码
export class DashboardService { constructor(private http: HttpClient, private configService: ConfigService, private cookieService: CookieService) { } getTimesheetDataByEmployee() { return this.configService.getConfig().pipe( switchMap((config: any) => { const empId = this.cookieService.get("employeeId"); console.log("EmployeeId : " + empId); const environment = config.environment.isLocal ? 'local' : 'dev'; const baseUrl = config[environment].baseUrl; const url = `${baseUrl}/TimeSheet?eid=${empId }`; return this.http.get<any[]>(url); }) ); } }
组件调用接口(无错误处理)
getEmployeeTimesheetData() { this.isLoading = true; this.dashboardService.getTimesheetDataByEmployee(this.cookieService.get("employeeId")). subscribe((data: any[]) => { this.isLoading = false; this.employeetimesheetData = data; this.groupTimesheetDataByMonth(); }); }
组件调用接口(添加catchError后)
getEmployeeTimesheetData() { this.isLoading = true; this.dashboardService.getTimesheetDataByEmployee(this.cookieService.get("employeeId")) .pipe( catchError((error) => { this.isLoading = false; console.error('Error fetching employee timesheet data:', error); return throwError(() => error); }) ) .subscribe((data: any[]) => { this.isLoading = false; this.employeetimesheetData = data; this.groupTimesheetDataByMonth(); }); }
问题核心原因
- Cookie作用域缺失:默认情况下
ngx-cookie-service设置的Cookie路径为当前路由,页面刷新后路由层级变化会导致Cookie无法跨路径读取 - 初始化时机问题:页面刷新时,
DashboardService在Angular初始化阶段就被实例化,此时浏览器Cookie还未完成加载,导致读取到空值;浏览器控制台能打印值是因为后续代码执行时Cookie已可用 - 错误处理的显性化:未添加
catchError时,Angular会静默吞掉Observable错误,导致问题被隐藏;添加错误处理后,空值引发的接口错误被正常捕获并抛出
解决方案
1. 全局化Cookie路径
修改登录时的Cookie设置代码,指定path='/'确保全站路由都能读取到Cookie:
this.cookieService.set('employeeId', response.employeeId, undefined, '/');
2. 确保Cookie读取时机可靠
在DashboardService中通过BehaviorSubject监听Cookie状态,避免初始化时读取空值:
import { BehaviorSubject, combineLatest } from 'rxjs'; import { switchMap, throwError } from 'rxjs/operators'; export class DashboardService { private employeeId$ = new BehaviorSubject<string>(this.cookieService.get('employeeId')); constructor( private http: HttpClient, private configService: ConfigService, private cookieService: CookieService ) { // 定时检查Cookie变化,更新Subject值 setInterval(() => { const currentId = this.cookieService.get('employeeId'); if (currentId !== this.employeeId$.value) { this.employeeId$.next(currentId); } }, 100); } getTimesheetDataByEmployee() { return combineLatest([this.configService.getConfig(), this.employeeId$]).pipe( switchMap(([config, empId]) => { if (!empId) { return throwError(() => new Error('Employee ID not found')); } const environment = config.environment.isLocal ? 'local' : 'dev'; const baseUrl = config[environment].baseUrl; const url = `${baseUrl}/TimeSheet?eid=${empId}`; return this.http.get<any[]>(url); }) ); } }
3. 添加路由守卫前置校验
创建路由守卫,确保访问Dashboard页面时Cookie已存在,避免无效请求:
import { Injectable } from '@angular/core'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { CookieService } from 'ngx-cookie-service'; @Injectable({ providedIn: 'root' }) export class AuthGuard implements CanActivate { constructor(private cookieService: CookieService, private router: Router) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { const empId = this.cookieService.get('employeeId'); if (empId) { return true; } this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; } }
在路由配置中绑定守卫:
const routes: Routes = [ { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }, // 其他路由配置 ];
4. 组件内前置校验
修改组件调用逻辑,先检查Cookie是否存在,不存在则直接跳转登录:
getEmployeeTimesheetData() { const empId = this.cookieService.get('employeeId'); if (!empId) { this.router.navigate(['/login']); return; } this.isLoading = true; this.dashboardService.getTimesheetDataByEmployee(empId) .pipe( catchError((error) => { this.isLoading = false; console.error('Error fetching employee timesheet data:', error); if (error.message.includes('Employee ID not found')) { this.router.navigate(['/login']); } return throwError(() => error); }) ) .subscribe((data: any[]) => { this.isLoading = false; this.employeetimesheetData = data; this.groupTimesheetDataByMonth(); }); }
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

