小程序中实现token过期重新登录再重新请求业务接口
该方法用于小程序token两个小时后过期,重新获取token再请求接口
1、新建一个封装请求接口文件,命名为request.js(我在utils文件夹下建request.js),代码如下:
let isRefreshing = true;
let subscribers = [];
function onAccessTokenFetched() {
subscribers.forEach((callback) => {
callback();
})
subscribers = [];
}
function addSubscriber(callback) {
subscribers.push(callback)
}
export class Http {
constructor() {}
request({
url,
data = {},
method,
header,
callback = ''
} = {}) {
let baseUrl = "xxxxx" //后台请求接口的公共部分
let _this = this;
return new Promise((resolve, reject) => {
uni.request({
url: baseUrl + url,
data,
method,
header: {
"token": uni.getStorageSync('token'),
"content-type": method == 'post' || method == 'POST' ?
'application/x-www-form-urlencoded' : 'application/json; charset=utf-8'
},
callback,
fail(res) {
reject(res)
},
complete: res => {
// callback token过期后重新请求接口,接口返回的数据
if (callback) return callback(res.data);
let statusCode = res.data.code;
let errText = res.data.msg;
// console.log(statusCode, 'statusCode')
if (statusCode == 404) {
console.log('接口不存在')
} else if (statusCode == 401 || statusCode == 10002 ) {
// 将需要重新执行的接口缓存到一个队列中
addSubscriber(() => {
_this.request({
url,
data,
method,
header,
callback: resolve
})
})
if (isRefreshing) {
getNewToken(`${baseUrl}/token/getToken`, url, data).then(() => {
// 依次去执行缓存的接口
onAccessTokenFetched();
isRefreshing = true;
})
}
isRefreshing = false;
} else if (statusCode == 200 || statusCode == 0 || statusCode == 1) {
// 登录成功,抛出数据
resolve(res.data)
}else if (statusCode == 10004) {
reject(res.data)
}else if(statusCode == 30001 || statusCode == 30002){
// 提示用户登录信息不全,需要获取用户信息
uni.navigateTo({
url:"/pages/login/login"
})
} else if (statusCode.startsWith('5')) {
uni.showModal({
content: '服务器报错,请重试!',
showCancel: false
});
}
}
})
})
}
}
// 获取token,token请求的接口通过形参传进来
const getNewToken = (url) => {
return new Promise((resolve, reject) => {
uni.login({
success(res) {
console.log(res)
uni.request({
url: url,
method: 'POST',
header: {
"content-type": "application/x-www-form-urlencoded"
},
data: {
code: res.code
},
success(res) {
console.log(res, 'token')
let r = res.data;
console.log(r, 'r')
// 将所有存储到观察者数组中的请求重新执行。
if (r.code == 0) {
const token = r.data;
// 使用本地缓存,把token存起来
uni.setStorageSync('token', token);
resolve(res);
}
}
})
},
fail(err) {
reject()
console.error('uni login fail', err);
}
});
})
}
2、使用方法,与utils文件夹同级建一个新的文件夹api,在api文件夹下新建index.js文件,代码如下
import { Http } from '../utils/request.js';
export class Index extends Http {
constructor() {
super();
}
// 获取轮播图 data代表参数
getBanner(data) {
return this.request({
url: '/getBanner',
method: 'GET',
data: data
});
}
}
3、再在api文件夹下新建一个js(banner.js)文件,用于引入index.js写的接口,代码如下
import {
Index
} from './index.js';
const API = new Index();
// 轮播图
export function getBanner(location_type) {
return new Promise(resolve => {
API.getBanner({
location_type: location_type
}).then(res => {
resolve(res.data)
})
})
}
4、在页面中使用,代码如下:
import { getBanner } from '../../api/banner.js'
export default {
data() {
return {
imgUrls: []
};
},
onLoad(options) {
// 请求轮播图接口
getBanner(0).then(res => {
this.imgUrls = res
})
},
methods: { }
};