项目包含app端,小程序端。限制同一个用户无法在多端同时登陆,新登陆会顶掉后登陆的。因为小程序没有退出功能,如果进入页面获取数据时token失效了,无法获取数据,页面显示一片空白,用户体验会很差,所以检测到token失效后重新登陆并重新调用对应api接口。
实现方式:
定义全局变量promiseQueue:[]来保存需要重新获取数据的异步请求参数,exeQueue来判断是否需要循环promiseQueue队列执行队列中的异步请求。
globalData: { exeQueue: true, promiseQueue: []}全局封装的登录接口,调用业务服务器通过code换取token
/** * 登录校验,获取openid * successCb 获取用户信息成功回调 */ login: function (successCb) { let that = this; wx.login({ success: function (res) { let requestObj = { url: "/xxx/login", method: 'post', dataobj: { code: res.code }, } wx.showLoading({ title: '努力加载中...', }) that.promiseRequest(requestObj).then((res) = { let resData = res.data.data; if (res.data.code == "000000") { // 成功获取useInfo保存起来。 that.globalData.userInfo = resData; successCb && successCb() } else { wx.hideLoading() wx.showModal({ title: '提示', content: res.data.errMsg || '网络错误!', showCancel: false }) } }).catch((errMsg) = { wx.hideLoading() console.log(errMsg); //错误提示信息 }); wx.hideLoading() } }) },全局封装的promise接口:
/** * 封装的promise * 参数: requestObj 请求成功回调 * throwError: true|false 如果传true则不判断code直接执行requestObj。否则code为100000时提示网络异常 */ promiseRequest: function (requestObj, throwError) { let that = this; return new Promise((resolve, reject) = { //网络请求 wx.request({ url: that.globalData.apiUrl + requestObj.url, method: requestObj.method, header: { ...that.globalData.userInfo, source: 'wxMini' }, data: JSON.stringify(requestObj.dataobj), success: function (res) { //返回取得的数据 let promiseQueue = that.globalData.promiseQueue; if (res.data.code == '000000' || throwError) { if (requestObj.resolve){ //如果是promise队列中的请求。 requestObj.resolve(res); let promiseQueueItem = promiseQueue.shift(); if (that.globalData.exeQueue){ //如果队列可执行则循环队列,保持队列只被循环一次。 that.globalData.exeQueue = false; //防止被多次循环。 while (promiseQueueItem) { that.promiseRequest(promiseQueueItem); promiseQueueItem = promiseQueue.shift(); that.globalData.promiseQueue = promiseQueue; } if (!promiseQueueItem) { that.globalData.exeQueue = true; that.globalData.needBeginLogin = true; } } }else{ resolve(res); } } else if (res.data.code == '600000' || res.data.code == '700000') { //token失效,重新调用login换取token requestObj.resolve = resolve; promiseQueue.push(requestObj); //请求失败了,把该请求放到promise队列,等待更新token后重新调用。 if (!that.globalData.needBeginLogin) { //如果不需要重新登录 return; } //防止重复调用login。 that.globalData.needBeginLogin = false; that.login(() = { //获取完token以后执行回调 //重新登陆以后调用一次队列中的promise;并设置队列为可循环状态。 let promiseQueueItem = promiseQueue.shift(); if (promiseQueueItem) { that.globalData.exeQueue = true; that.promiseRequest(promiseQueueItem); that.globalData.promiseQueue = promiseQueue; } }, true) } else { wx.hideLoading() wx.showModal({ title: '提示', content: res.data.message }) } }, error: function (e) { wx.hideLoading() reject(e); } }) }); }调用接口
/** 如果调用该接口是状态吗返回60000或70000,则需要重新调用login获取新的token。因为该次请求已失败,会把本次请求参数以及回到放到全局参数promiseQueue中,登录成功后会循环promiseQueue重新发起请求。*/let requestObj = { url: `/xxx/index`, method: 'post' }; wx.showLoading({ title: '努力加载中...', }) app.promiseRequest(requestObj).then((res) = { that.setData(res.data.data) wx.hideLoading() }).catch((errMsg) = { wx.hideLoading() console.log(errMsg);//错误提示信息 });其他解决方案
上面代码逻辑有点复杂,不过仔细梳理一遍还是能看懂的。如果嫌麻烦可以使用下面方法
that.login(() = { //登录成功回调var page = getCurrentPages().pop(); //获取当前页面实例if (page == undefined || page == null) return; page.onLoad(); //调用实例的onLoad方法重新加载数据;}当然这样会重新调用页面所有方法,如果有部分接口已经正确返回数据还会重新获取。如果能忍,这个更简单。













