流程图
贴下封装的request.js代码
import axios from "axios";
import JsCookie from "js-cookie";
import { ElMessage } from 'element-plus'
// 创建并配置一个新的axios
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 60000, // 请求超时时间 毫秒
withCredentials: true, // 异步请求时是否携带cookie,跨域请求设置
headers: { // 设置后端需要的传参类型
"Content-Type": "application/json", //设置post请求头
"Client": "front", // 所属客户端
// "Authorization": "",
// "X-Requested-With": "XMLHttpRequest",
},
});
//service.defaults.withCredentials = true; //跨域请求设置
//axios.defaults.headers.post["Content-Type"] = "application/json"; //设置post请求头
// 添加请求拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么。。。
let tokenInfo = ""
if(!config.url.includes('userLogin/refreshtoken')){ //判断是否为刷新token请求--否
tokenInfo = JsCookie.get("accessToken") ? JSON.parse(JsCookie.get("accessToken")) : ""
}else{ //判断是否为刷新token请求--是
tokenInfo = JsCookie.get("refreshToken") ? JSON.parse(JsCookie.get("refreshToken")) : ""
}
if(tokenInfo){ //配置请求token
config.headers['Authorization'] = tokenInfo
}
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
let isTokenRefreshing = false // token是否正在刷新
let requestList = [] //正在等待请求的接口队列
// 添加响应拦截器
service.interceptors.response.use(
(response) => {
const res = response.data;
if (res.code == 100009 || res.code == 100005) { // 对通用token令牌过期的处理
if(!isTokenRefreshing){ //判断当前不处于刷新阶段--则进行刷新操作
isTokenRefreshing = true // 上锁
const requestconfig = {
url: `/iam/userLogin/refreshtoken`,
method: "get",
}
return service(requestconfig).then(_res => {
if(_res.code == 200000){ //刷新成功--将新的通用token和刷新token都进行更新;并执行requestList等待队列里的接口请求
// 保存通用token
let accessTokenExpireTime = new Date(new Date().getTime() + _res.data.expire_in)
JsCookie.set("accessToken", JSON.stringify(_res.data.access_token), { expires: accessTokenExpireTime });
// 保存刷新token
let refreshTokenExpireTime = new Date(new Date().getTime() + _res.data.refresh_expire_in)
JsCookie.set("refreshToken", JSON.stringify(_res.data.refresh_token), { expires: refreshTokenExpireTime });
//执行后续推入到requestList队列中的请求,(requestList中存的不是请求参数,而是请求的Promise函数,这里直接拿来执行就好)
requestList.forEach(run => run())
//将请求队列置空
requestList = []
//重新执行一下本次未执行成功的请求并返回
return service(response.config);
}else if(_res.code == 100010){ //刷新token也过期了--移除用户登录相关信息,并提示用户重新登录
JsCookie.remove("accountInfo"); // 移除用户信息
JsCookie.remove("accessToken"); // 移除通用token
JsCookie.remove("refreshToken"); // 移除刷新token
ElMessage.warning("您尚未登录或登录已过期,请重新登录哦");
return Promise.reject(new Error(_res.msg || "Error"));
}
}).catch(()=>{
}).finally(()=>{
isTokenRefreshing = false //解锁
})
}else{ //判断当前处于token刷新阶段--将后续接口推入等待请求队列,等待刷新token接口请求完毕后执行后续请求队列
return new Promise(resolve => {
//这里加入的是一个promise的解析函数,将响应的config配置对应解析的请求函数存到requestList中,等到刷新token回调后再执行
requestList.push(() => {
resolve(service(response.config));
})
})
}
} else {
// 其他情况则返回结果,对应状态code需在具体请求函数里判断
return res;
}
},
(error) => {
ElMessage.warning(error.msg || "服务器开小差了呢,请稍后再试~");
return Promise.reject(error);
}
);
export default service;