You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ngx-cookie-service页面刷新失效,添加catchError后报错求助

问题场景

  • Angular项目通过ngx-cookie-service存储登录态,登录成功后设置employeeId Cookie
  • 页面刷新时,浏览器控制台能正常打印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();
    });
}

问题核心原因

  1. Cookie作用域缺失:默认情况下ngx-cookie-service设置的Cookie路径为当前路由,页面刷新后路由层级变化会导致Cookie无法跨路径读取
  2. 初始化时机问题:页面刷新时,DashboardService在Angular初始化阶段就被实例化,此时浏览器Cookie还未完成加载,导致读取到空值;浏览器控制台能打印值是因为后续代码执行时Cookie已可用
  3. 错误处理的显性化:未添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:35:00