专业编程教程与实战项目分享平台

网站首页 > 技术文章 正文

TypeScript Axios 实现无感刷新Token

ins518 2025-03-18 23:07:59 技术文章 7 ℃ 0 评论

在前端开发中,无感刷新 Token 是一种常见的优化用户体验的技术。它的核心思想是:当用户的 Access Token 过期时,自动使用 Refresh Token 获取新的 Access Token,而不需要用户重新登录。以下是使用 TypeScript 和 Axios 实现无感刷新 Token 的完整方案。


1.实现思路

  1. 拦截请求:使用 Axios 的请求拦截器,在每次请求时检查 Access Token 是否过期。
  2. 拦截响应:使用 Axios 的响应拦截器,检查响应状态码。如果 Access Token 过期(如 401 错误),则尝试使用 Refresh Token 获取新的 Access Token。
  3. 重试请求:在获取新的 Access Token 后,重新发送之前失败的请求。
  4. 避免重复刷新:在刷新 Token 的过程中,如果有多个请求同时失败,只刷新一次 Token。

2.代码实现

实现无感刷新 Token

refresh-token.ts

import { setToken, setRefreshToken } from "./token";
let refreshTokenPromise: Promise | null = null;

/**
 *刷新token
 *
 * @export
 * @return {*}  {Promise}
 */
export async function refreshToken(): Promise {
    if (refreshTokenPromise) {
        return refreshTokenPromise;
    }
    refreshTokenPromise = new Promise(async(resolve) => {
        //调用刷新token接口  _isRefreshToken 标记请求是刷新token请求
        const { data } = await http.get("/auth/refreshToken", { headers: { Authorization: getRefreshToken() }, _isRefreshToken: true });
        //存储刷新后的token
        setToken(data.token);
        setRefreshToken(data.refreshToken);
        resolve();
    });

  refreshTokenPromise.finally(() => {
    refreshTokenPromise = null;
  });
  return refreshTokenPromise;
}

/**
 *判断是否是刷新token请求
 *
 * @export
 * @param {*} config 请求配置
 * @return {boolean} 
 */
export function isRefreshToken(config: any): boolean {
    return !!config._isRefreshToken;
}

axios 响应拦截处理请求401 刷新token

import { refreshToken, isRefreshToken } from "./refresh-token"
import { getToken } from "./token"; 
import config from "@/config";

const $http = axios.create({
    // 默认地址
    baseURL: config.apiBasePath,
    // 设置超时时间(90s)
    timeout: ResultEnum.TIMEOUT as number,
    // 跨域时候允许携带凭证
    withCredentials: false
});

$http.interceptors.response.use(
    response => {
        const { data } = response;
        return data;
    },
    async(error) => {
        const { response } = error;
        //token过期
        if (response?.status === 401) {
            //判断当前请求是否是刷新token的请求
            if (!isRefreshToken(response.config)) {
                await refreshToken();
                //刷新token成功 用新的token重新发起请求
                response.config.headers.Authorization = getToken();
                return await $http.request(config);
            } else {
                //token刷新失败 跳转登录页
            }
        }
    }
)

3.关键点解析

  1. 响应拦截器
  2. 如果响应状态码为 401(未授权),则尝试使用 Refresh Token 刷新 Access Token。
  3. 使用Promise的唯一性 刷新Token,待刷新完成后重新发送请求。
  4. 避免重复刷新
  5. 判断当前请求是否是刷新Token的请求,确保同一时间只刷新一次 Token。、
  6. 刷新失败 (refreshToken 已过期) 跳转登录页

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表