Skip to content

Commit 27bc135

Browse files
committed
fix: 修复当token过期后,如果页面有多个请求会重复刷新token
1 parent 4d91d20 commit 27bc135

File tree

3 files changed

+50
-20
lines changed

3 files changed

+50
-20
lines changed

mock/refreshToken.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export default [
1010
return {
1111
success: true,
1212
data: {
13-
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin",
14-
refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh",
13+
accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin",
14+
refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh",
1515
// `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。
1616
expires: "2023/10/30 23:59:59"
1717
}

src/utils/auth.ts

+5
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,8 @@ export function removeToken() {
7070
Cookies.remove(TokenKey);
7171
sessionStorage.removeItem(sessionKey);
7272
}
73+
74+
/** 格式化token(jwt格式) */
75+
export const formatToken = (token: string): string => {
76+
return "Bearer " + token;
77+
};

src/utils/http/index.ts

+43-18
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { stringify } from "qs";
1313
import NProgress from "../progress";
1414
// import { loadEnv } from "@build/index";
15-
import { getToken } from "@/utils/auth";
15+
import { getToken, formatToken } from "@/utils/auth";
1616
import { useUserStoreHook } from "@/store/modules/user";
1717

1818
// 加载环境变量 VITE_PROXY_DOMAIN(开发环境) VITE_PROXY_DOMAIN_REAL(打包后的线上环境)
@@ -43,27 +43,43 @@ class PureHttp {
4343
this.httpInterceptorsRequest();
4444
this.httpInterceptorsResponse();
4545
}
46+
47+
/** token过期后,暂存待执行的请求 */
48+
private static requests = [];
49+
50+
/** 防止重复刷新token */
51+
private static isRefreshing = false;
52+
4653
/** 初始化配置对象 */
4754
private static initConfig: PureHttpRequestConfig = {};
4855

4956
/** 保存当前Axios实例对象 */
5057
private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
5158

59+
/** 重连原始请求 */
60+
private static retryOriginalRequest(config: PureHttpRequestConfig) {
61+
return new Promise(resolve => {
62+
PureHttp.requests.push((token: string) => {
63+
config.headers["Authorization"] = formatToken(token);
64+
resolve(config);
65+
});
66+
});
67+
}
68+
5269
/** 请求拦截 */
5370
private httpInterceptorsRequest(): void {
5471
PureHttp.axiosInstance.interceptors.request.use(
5572
async (config: PureHttpRequestConfig) => {
56-
const $config = config;
5773
// 开启进度条动画
5874
NProgress.start();
5975
// 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
6076
if (typeof config.beforeRequestCallback === "function") {
61-
config.beforeRequestCallback($config);
62-
return $config;
77+
config.beforeRequestCallback(config);
78+
return config;
6379
}
6480
if (PureHttp.initConfig.beforeRequestCallback) {
65-
PureHttp.initConfig.beforeRequestCallback($config);
66-
return $config;
81+
PureHttp.initConfig.beforeRequestCallback(config);
82+
return config;
6783
}
6884
/** 请求白名单,放置一些不需要token的接口(通过设置请求白名单,防止token过期后再请求造成的死循环问题) */
6985
const whiteList = ["/refreshToken", "/login"];
@@ -75,21 +91,30 @@ class PureHttp {
7591
const now = new Date().getTime();
7692
const expired = parseInt(data.expires) - now <= 0;
7793
if (expired) {
78-
// token过期刷新
79-
useUserStoreHook()
80-
.handRefreshToken({ refreshToken: data.refreshToken })
81-
.then(res => {
82-
config.headers["Authorization"] =
83-
"Bearer " + res.data.accessToken;
84-
resolve($config);
85-
});
94+
if (!PureHttp.isRefreshing) {
95+
PureHttp.isRefreshing = true;
96+
// token过期刷新
97+
useUserStoreHook()
98+
.handRefreshToken({ refreshToken: data.refreshToken })
99+
.then(res => {
100+
const token = res.data.accessToken;
101+
config.headers["Authorization"] = formatToken(token);
102+
PureHttp.requests.forEach(cb => cb(token));
103+
PureHttp.requests = [];
104+
})
105+
.finally(() => {
106+
PureHttp.isRefreshing = false;
107+
});
108+
}
109+
resolve(PureHttp.retryOriginalRequest(config));
86110
} else {
87-
config.headers["Authorization"] =
88-
"Bearer " + data.accessToken;
89-
resolve($config);
111+
config.headers["Authorization"] = formatToken(
112+
data.accessToken
113+
);
114+
resolve(config);
90115
}
91116
} else {
92-
resolve($config);
117+
resolve(config);
93118
}
94119
});
95120
},

0 commit comments

Comments
 (0)