您现在的位置是:首页 >技术杂谈 >TypeScript Axios 实现无感刷新Token网站首页技术杂谈

TypeScript Axios 实现无感刷新Token

YouzAi@ 2025-03-21 00:01:03
简介axios promise刷新token 拦截

在前端开发中,无感刷新 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<void> | null = null;

/**
 *刷新token
 *
 * @export
 * @return {*}  {Promise<void>}
 */
export async function refreshToken(): Promise<void> {
	if (refreshTokenPromise) {
		return refreshTokenPromise;
	}
	refreshTokenPromise = new Promise<void>(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. 响应拦截器

    • 如果响应状态码为 401(未授权),则尝试使用 Refresh Token 刷新 Access Token。
    • 使用Promise的唯一性 刷新Token,待刷新完成后重新发送请求。
  2. 避免重复刷新

    • 判断当前请求是否是刷新Token的请求,确保同一时间只刷新一次 Token。、
    • 刷新失败 (refreshToken 已过期) 跳转登录页

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。