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

如何在Angular拦截器中调用Refresh Token API刷新访问令牌?

Angular拦截器内调用刷新Token接口实现方案

要实现先刷新Token再发送原请求的逻辑,核心要注意避免刷新Token接口被当前拦截器拦截造成死循环,再借助RxJS操作符实现请求串行处理即可,以下是完整实现:

修改后完整拦截器代码

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpClient
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { switchMap, catchError } from 'rxjs/operators';
import { Router } from '@angular/router'; // 可选,用于刷新失败跳登录页

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

  constructor(
    private http: HttpClient,
    private router: Router // 可选注入
  ) {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    // 1. 放行刷新Token的请求,避免循环调用
    if (request.url.includes('/api/refresh-token')) {
      return next.handle(request);
    }

    // 2. 校验Token是否需要刷新,可自行替换校验逻辑
    const needRefresh = this.checkTokenNeedRefresh();
    const accessToken = localStorage.getItem('access_token');

    // 3. 不需要刷新直接携带原有Token发送请求
    if (!needRefresh && accessToken) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${accessToken}`
        }
      });
      return next.handle(request);
    }

    // 4. 需要刷新Token,先调用刷新接口再发送原请求
    return this.http.post('/api/refresh-token', {
      refresh_token: localStorage.getItem('refresh_token')
    }).pipe(
      switchMap((res: any) => {
        // 存储新返回的Token和有效期
        localStorage.setItem('access_token', res.access_token);
        localStorage.setItem('refresh_token', res.refresh_token);
        localStorage.setItem('token_expire_time', String(Date.now() + res.expires_in * 1000));

        // 克隆原请求,携带新Token
        const newRequest = request.clone({
          setHeaders: {
            Authorization: `Bearer ${res.access_token}`
          }
        });
        // 发送原请求
        return next.handle(newRequest);
      }),
      catchError(err => {
        // 刷新Token失败,清除本地信息跳转到登录页
        localStorage.clear();
        this.router.navigate(['/login']);
        return throwError(() => err);
      })
    );
  }

  // 自定义Token有效期校验逻辑,示例为提前5分钟刷新
  private checkTokenNeedRefresh(): boolean {
    const expireTime = Number(localStorage.getItem('token_expire_time'));
    if (!expireTime) return true;
    // 剩余有效期小于5分钟触发刷新
    return Date.now() > expireTime - 5 * 60 * 1000;
  }
}

核心注意点

  • 接口路径替换:代码里的/api/refresh-token需要替换成你自己业务的刷新Token接口地址
  • 避免死循环:必须先判断当前请求是不是刷新Token的接口,直接放行,否则刷新请求也会被拦截器拦截,再次触发刷新逻辑造成死循环
  • 错误处理:刷新Token失败后要及时清除本地存储的用户信息,跳转到登录页避免异常状态
  • 多请求并发优化(可选):如果同时有多个请求触发Token刷新,可以加全局锁避免重复调用刷新接口,所有等待的请求等刷新完成后再依次发送。

内容的提问来源于stack exchange,提问作者Ajay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 06:45:04