需求背景
按以前的做法,前端在token过期后会跳回登录页,要求重新登录,这样会打断用户操作,所以提出需求:要无感刷新token
代码设计背景
1.后端:每个用户的token存入user表里这个用户的token字段,每次登录即更新token字段;
2.前端:利用axios发请求
3.前后端共用:前端把token存在headers的acces_token中,每个请求后端都进行校验token是否过期(实现方式看2020-11-04 node端做用户token校验(jsonwebtoken)),token过期返回特定code供前端在拦截器里做判断。
设计思路
在返回拦截器判断token是否过期,如果过期,重新发送登录请求以刷新token,然后重新发起token过期时发送的请求。
具体实现思路可查看【axios如何利用promise无痛刷新token】
返回拦截器代码
最终实现目标:
1.拦截器收到token过期的code,请求登录接口,成功后再请求过期时发送的请求
2.防止多次刷新token
3.解决多个请求的重新发送
const axios = Axios.create(axios_config); // 创建axiosconst REFRESH_TOKEN_CODE = 996; // 和后端统一定义996是token过期的code// 响应拦截器let isRefreshing = false; // 是否正在刷新tokenlet requests = []; // 等待token刷新后重新发送的请求队列axios.interceptors.response.use(async res => {// 返回成功有code的情况,返回 res.data.dataif (res.data && res.data.code) {if (res.data.code === 200) {return res.data.data != undefined ? res.data.data : {}; // code 200 也可能没有 data} else {// 自动刷新token逻辑const config = res.config; // 本次失败请求的信息if (res.data.code === REFRESH_TOKEN_CODE) {if (!isRefreshing) {isRefreshing = true;try {const userInfo = JSON.parse(sessionStorage.getItem('userInfo')); // 从缓存中读取用户信息,用于登录const params = {... // 登录请求的参数};const loginRes = await login(params); // 登录请求sessionStorage.setItem('userInfo', JSON.stringify(loginRes)); // 再存入缓存config.headers['access_token'] = loginRes.token;// 已经刷新了token,将所有队列中的请求进行重试requests.forEach(cb => cb(loginRes.token));requests = []; // 重试完了别忘了清空这个队列return axios(config); // 第一个重新发送的请求,其他请求都在else中} catch (e) {console.log(e);vm.$router.push({ path: '/login' });} finally {isRefreshing = false;}} else {// 正在刷新token,返回一个未执行resolve的promisereturn new Promise(resolve => {// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行requests.push(token => {config.headers['access_token'] = token;resolve(axios(config));});});}return;}vm.$message.closeAll();vm.$message.error(res.data.msg);// if (LOGOUT_RES_CODE.includes(res.data.code)) {// vm.$router.push({ path: '/login' });// }return Promise.reject({code: res.data.code,msg: res.data.msg || '',});}}return res.data;},error => {... // 省略部分代码return Promise.reject(error);});
