最近使用京东开发的Taro框架开发微信小程序,开发小程序的自动登录,后台提供了微信授权登录后,通过openid可以直接获token的免登录接口,但是这个接口给的token2个小时过期,为避免用户使用过程中token突然过期,需要写一个拦截器判断token是否过期,如果过期自动调免登录接口,更新token。先上代码。
interceptors.js//过滤器js文件
import Taro from"@tarojs/taro";
import { setStorage, getStorage, getSign, delStorage } from"@utils/tools";
import getBaseUrl from"./baseUrl";
/**
* 注册token刷新成功后存储登录状态方式
*/
var setTokenStatus = null;
var setTokenConfig =function(cb) {
setTokenStatus = typeof cb ==="function"? cb : null;
};
//拦截器 chain.requestParams 代表请求参数
const customInterceptor = chain => {
const requestParams = chain.requestParams;
拦截器内最后需要调用 chain.proceed(requestParams) 以调用下一个拦截器或发起请求。
returnchain.proceed(requestParams).then(res => {
//当业务接口返回 token过期时(code === 100010101) 重新自动登录reconnect 然后在调一次业务接口
if(res.data.code === 100010101 ) {
returnreconnect(requestParams);
}
returnres;
});
};
const tokenService = {
refreshAxios: null,
refreshToken() {
if(this.refreshAxios) {
//正在请求中的锁 使用单例模式
returnthis.refreshAxios;
}
this.refreshAxios = new Promise((resolve, reject) => {
const url ="=/wechat/token";//后台免登录接口 得到token
const contentType ="application/x-www-form-urlencoded;charset=UTF-8"; //post请求方式
Taro.login().then(res => {
const option = {
url: getBaseUrl(url,"1") + url,
method:"POST",
timeout: 2000,
data: { code: res.code },
header: {
"content-type": contentType
},
fail: res => {
console.log("checkCode失败了", res);
}
};
Taro.request(option)
.then(
response => {
const { code, data } = response.data;
if(code === 0 && data) {
if(setTokenStatus === null) {
const {
accessToken,
refreshToken,
sessionKey,
openid,
wechatId
} = data;
const token = {
token: accessToken,
refreshToken: refreshToken
};
setStorage(
"ELDERLY_TOKEN_KEY",
JSON.stringify(token),
"async"
);
setStorage(
"ELDERLY_SESSIONKEY",
JSON.stringify({ sessionKey, openId: openid, wechatId })
);
}else{
setTokenStatus(data.accessToken, data.refreshToken);
}
this.refreshAxios = null;
resolve(response);
}else{
//如果重新登录失败 先做暂时处理 清空本地token 后期加跳转登录页
delStorage("ELDERLY_USERINFO","async");
delStorage("ELDERLY_TOKEN_KEY","async");
Taro.navigateTo({
url:"pages/login/index"
});
// setTimeout(() => {
// taro.showModal({
// title:'提示',
// content:'当前网络异常,请您稍后再试!',
// success:function(res) {
//if(res.confirm) {
// console.log('用户点击确定')
// }elseif(res.cancel) {
// console.log('用户点击取消')
// }
// }
// })
// }, 800);
}
},
err => {
// console.log('checkCode失败了');
this.refreshAxios = null;
returnreject(err);
}
)
.catch(err => {
// console.log("checkCode失败了");
this.refreshAxios = null;
reject(err);
});
});
}).catch(err => {
console.log("checkCode失败了");
console.log(err);
});
returnthis.refreshAxios;
}
};
/**
* 重连
* @param {} config
* @returns promise
*/
functionreconnect(config) {
returntokenService.refreshToken().then(
() => {
//刷新token,返回token的promise
//重连时,重新计算签名,并覆盖旧的授权参数
const { data, method, url, header } = config;
const tokenData = getStorage("ELDERLY_TOKEN_KEY")
? JSON.parse(getStorage("ELDERLY_TOKEN_KEY"))
: {};
data.accessToken = tokenData.token;
data.timestamp = new Date().getTime();
delete data.sign; //删除原有的sign 防止签名错误
data.sign = getSign(method, url, data);
const option = {
url: url,
method: method,
timeout: 2000,
data: data,
header: header
};
returnTaro.request(option).finally(res => {
returnres;
});
},
err => {
returnerr;
}
);
}
const interceptors = [customInterceptor];
exportdefault interceptors;