uniapp静默授权,无感刷新token。

1,496 阅读2分钟

wallhaven-rrow61.png

项目要求: uniapp项目 vue2 ,微信,支付宝小程序 亲测有效。

需求 =>小程序静默授权之后进行登录,需要保证用户在任何操作过程中都不能让token过期,即过期时进行无感刷新。

核心思路 => 所有登录操作以及静默授权,以及刷新token操作都在响应拦截器进行统一处理,应用Promise队列的方式吧请求挂起,使用await阻塞请求的响应,保证在第一次请求失败后,拿到响应码,进行token的换取,拿到最新token之后把队列的请求逐个恢复。

提供给需要帮助的小伙伴,不足的地方欢迎指出。

项目依赖:使用第三方sdk luch-request ,自行导入项目可以使用npm,也可以直接把包clone放到项目文件夹进行导入。

代码部分

import Request from "@/js_sdk/luch-request/index.js"; //第三方sdk文件
import store from "@/store/index.js"; //封装的vuex action登录接口

const http = new Request();

// 是否正在刷新token的标记
let isRefreshing = false;
// 重试请求队列
let requests = [];

http.setConfig((config) => {
	/* 设置全局配置 */
	config.baseURL = '服务器路径'; /* 根域名不同 */	
	config.dataType = "string"; //响应体转成string模式(本人项目要求), 如果不需要可以去掉,默认是json
	config.header = {
		...config.header,
	}; //解析请求头信息
	return config;
});

/**
 * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject)
 * @param { Number } statusCode - 请求响应体statusCode(只读)
 * @return { Boolean } 如果为true,则 resolve, 否则 reject
 */
http.validateStatus = (statusCode) => {
	return statusCode === 200;
};

http.interceptors.request.use((config, cancel) => {
	if (config.url != "刷新token接口路径" ) {
		uni.showLoading({
			title: "加载中...",
		});
	} //为了登录或者刷新token的接口不开启Loading,根据自己项目需求删减。
	/* 请求之前拦截器 */
	const token = uni.getStorageSync("token");//获取token
	if (token) {
		config.header = {
			...config.header,
			"authorization": "Bearer " + token,	
		};
	}
	return config;
});

http.interceptors.response.use(
	(response) => {
		uni.hideLoading();
		/* 请求之后拦截器 */
		// const res = response.data
		if (res.code === 1) {
			//提示错误信息
			uni.showToast({
				title: res.msg,
				duration: 1500,
			});
			return Promise.reject(response);
		} else {
			return res;
		}
	},
	async (response) => {
		switch (response.statusCode) {
			case 424:
				if (!isRefreshing) {
					// 正在刷新
					isRefreshing = true;
					const accountInfo = uni.getAccountInfoSync(); //获取登录的appId
					// #ifdef MP-WEIXIN
					const res = await uni.login({
						provider: "weixin",
						onlyAuthorize: true,
					}); //拿到微信的code
					uni.clearStorageSync() //清除缓存信息
					await store.dispatch("login", {
						code: res[1].code,
                                                appId:accountInfo.miniProgram.appId 
					});
                                        //vuex 登录获取token接口,根据个人项目封装传参
					// #endif  
                                        
                                        // 本项目兼容的平台过多,再此仅以微信小程序为例子
					requests.forEach(async ({
						fn,
						resolve
					}) => {
						// 逐个按请求队列顺序重新发起请求
						const ress = await fn();
						resolve(ress);
					});
					requests = []; // 清空请求队列
					isRefreshing = false;
					const resData = await http.request(response.config);//恢复请求
					return resData;
				} else {
					// 同时并发出现的请求 新的token没回来之前 先用promise 存入等待队列中
					return new Promise((resolve) => {
						const fn = () => Promise.resolve(http.request(response.config));
						requests.push({
							fn,
							resolve,
						});
					});
				}
			default:
				return uni.showToast({
					title: "服务器错误",
					duration: 1500,
				});
		}
	}
);

export function request(options = {}) {
	return http.request(options);
}

export default request;