小程序中实现token过期重新登录再重新请求业务接口

改造于 https://blog.csdn.net/yutao618/article/details/114979512
该方法用于小程序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: { }
};

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐