token无感刷新的原理很简单,使用双token,分别为accessToken
和refreshToken
,正常都是携带accessToken
进行验证。当返回状态码表示token过期时,再携带refreshToken
重新获取accessToken
,然后重新携带accessToken
发起请求。
// axiox.ts
import axios from "axios";
import { AxiosRetry } from './axiosClass'
axios.defaults.baseURL='http://127.0.0.1:3000'
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
// 在请求头中添加token
config.headers.Authorization = localStorage.getItem("accessToken");
if (config.url == "/refreshToken") {
config.headers.Authorization = localStorage.getItem("refreshToken");
}
return config;
},
);
/**先到拦截器*/
axios.interceptors.response.use(res => {
if (res.status != 200) {
return Promise.reject(res.data);
}
return Promise.resolve(res.data)
});
const axiosRetry = new AxiosRetry({
onSuccess: (res) => {
let { accessToken } = res.data
localStorage.setItem("accessToken", accessToken);
},
onError: () => {
console.log('refreshToken过期,需要重新登录');
},
});
export const request = (url: string) => {
return axiosRetry.requestWrapper(() => {
return axios({
method: "get",
url: `${url}`,
})
});
}
// axiosClass.ts
import { Axios } from 'axios';
import axios from 'axios';
export class AxiosRetry {
private fetchNewTokenPromise: Promise<any> | null = null;
private onSuccess: (res: any) => any;
private onError: () => any;
constructor({
onSuccess,
onError,
}: {
onSuccess: (res: any) => any;
onError: () => any;
}) {
this.onSuccess = onSuccess;
this.onError = onError;
}
/** 发送请求*/
requestWrapper<T>(request: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
/** 将请求接口的函数保存*/
const requestFn = request;
return request().then((res) => {
//拦截器处理后的数据
resolve(res);
}).catch(err => {
//token过期或者没有token
if (err.response.status === 401) {
if (!this.fetchNewTokenPromise) {
this.fetchNewTokenPromise = this.fetchNewToken();
}
this.fetchNewTokenPromise.then(() => {
return requestFn();
}).then((res) => {
resolve(res);
this.fetchNewTokenPromise = null;
}).catch((err) => {
reject(err);
this.fetchNewTokenPromise = null;
});
} else {
reject(err);
}
});
});
}
// 获取新的token
fetchNewToken() {
return axios({
method: "post",
url: `/refreshToken`,
}).then((res) => {
this.onSuccess(res)
}).catch((err) => {
this.onError();
//表示refreshToken过期,需要重新登录
if (err.response.status === 401) {
return Promise.reject(
new Error("refreshToken过期,需要重新登录")
);
}
//表示发生了其他错误
else {
return Promise.reject(err);
}
})
}
}
评论 (0)