其他
微信小程序如何优雅的处理token失效
前言
当我们打开小程序调用完wx.login方法获取到token后,我们就可以在请求header里设置token进去访问后端了.但我们在平时使用token时。肯定是会给token设置一个有效期的。在这样的前提下,如果你没有做一些刷新token的机制且长时间不操作的话。会导致接下来接口请求失效报token异常。那么我们如何在小程序中实现统一的请求接口报token错误时。先去请求一下wx.login接口然后再一次调用需要请求的接口呢?如图:
代码实现
let isRefreshing = true;
let subscribers = [];
var app = getApp();
let baseUrl = app.globalData.baseUrl;
function onAccessTokenFetched() {
subscribers.forEach((callback) => {
callback();
})
subscribers = [];
}
function addSubscriber(callback) {
subscribers.push(callback)
}
export class Http {
constructor() {}
req({type, url, data,callback=''}={}) {
let userInfo = wx.getStorageSync('userInfo');
var header={}
if(userInfo){
header = { // 根据需求设置请求头Authorization
'content-type': 'application/json',
"Authorization": userInfo.token,
};
}
let _this = this;
return new Promise((resolve, reject) => { // 返回一个Promise
wx.request({
url: baseUrl + url, // 请求地址
data: data, // 请求参数v
header: header,
method: type,
success: function (res){
if (callback) return callback(res);
if (res.data.code == 404) {
console.log('接口不存在')
} else if (res.data.code == 403) {
// 将需要重新执行的接口缓存到一个队列中
addSubscriber(() => {
_this.req({ type,url, data, callback: resolve })
})
if (isRefreshing) {
getNewToken(url, data).then(() => {
// 依次去执行缓存的接口
onAccessTokenFetched();
isRefreshing = true;
})
}
isRefreshing = false;
} else if (res.data.code == 200) {
resolve(res)
} else{
wx.showModal({ content: res.data.msg, showCancel: false });
}
},
fail: function (err ) {
reject(err)
},
enableCache: true,
timeout: 600000, //接口请求超时时间
complete: function (vv) { // 接口调用结束的回调函数(调用成功、失败都会执行)
// console.log(vv);
}
})
}).catch( err => {
console.log(err);
})
}
const getNewToken = () => {
return new Promise((resolve, reject) => {
wx.login({
timeout: 5000,
success(res){
wx.request({
url: baseUrl+'/fLogin?code='+res.code,
method: 'GET',
success:(resp)=>{
app.globalData = {
userInfo: resp.data.userInfo,
UserLogin: true
}
// 缓存到本地
wx.setStorageSync('userInfo', resp.data.userInfo)
resolve(res)
}
})
}
})
})
}
api.js用于统一定义我们的请求后端的接口。你也可以不同模块分别定义接口.
import {Http} from './http'
export class Index extends Http {
constructor() {
super();
}
// 获取联系方式列表
getPhoneList(data) {
return this.req({
type: 'GET',
url: '/system/data/fList',
data:data
});
}
setStoreSyncSecond(key, value, time){
wx.setStorageSync(key, value)
var t = time ? time : 24;
var seconds = parseInt(t * 3600);
if (seconds > 0) {
var timestamp = Date.parse(new Date());
timestamp = timestamp / 1000 + seconds;
wx.setStorageSync(key + 'dtime', timestamp + "")
} else {
wx.removeStorageSync(key + 'dtime')
}
}
getStorageSyncTime(key, def) {
var deadtime = parseInt(wx.getStorageSync(key + 'dtime'))
if (deadtime) {
if (parseInt(deadtime) < Date.parse(new Date()) / 1000) {
wx.removeStorageSync(key);
wx.removeStorageSync(key + 'dtime');
if (def) { return def; } else { return; }
}
}
var res = wx.getStorageSync(key);
if (res) {
return res;
} else if (def) {
return def;
} else {
return;
}
}
}
03如何控制弹出框或者某个业务多久之内只显示一次在api.js中我们分别定义了setStoreSyncSecond跟getStorageSyncTime方法。通过这两个方法。我们可以把设置到storeData中的数据保存时间。
具体使用方法:
onLoad(options) {
//获取该key在storeData中的数据,如果没有,则显示弹出框
let show = API.getStorageSyncTime('show_notic',0)
let that = this
if(show ===undefined || show===0){
//显示弹出框后要设置该key多久过期。如1个小时。具体时间可以在方法里控制
API.setStoreSyncSecond('show_notic','1',1)
this.setData({
show:true
})
//弹出宽显示10秒自动关闭
setTimeout(function(){
that.setData({
show:false
})
},10000)
}
}
点击关注我吧,发现更多有用分享。让你的技术得到更大提升
文中代码参考示例,可点击小程序,进入便民电话本
如需源码学习,可公众号内发送 "工具箱"