最近使用京東開發的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;