简介:
在微信小程序开发过程中,网络请求是开发中最基础也是最核心的需求,封装一个稳定且可用性高的请求也显得尤为重要。通常封装的内容除了入参之外,更多的是请求中的异常处理。在处理 token 异常方面的做法,通过维护请求队列,实现重发请求,减少 token 重复请求。
步骤:
- 正常业务请求
- 检查该请求地址是否需要登录后访问,如果不需要,则直接访问,该请求结束
- 如果需要,则判断缓存Token是否存在,如果不存在,则直接跳转登录,如果存在,进入步骤4
- 请求后端接口,请求token未过期,则正常返回业务数据,如果请求token过期,则进入步骤5
- 调用Token刷新接口,刷新token过期,则直接跳转登录
- 刷新token没有过期,则获取token,并存入缓存 进入步骤7
- 在客户无感知(无痛)情况下继续请求最初的业务请求,将结果返回
需要注意:请求如果没有限制处理,有多个请求同时到达,就会发起多个 updateToken 请求,其实我们并不想这样,只需要请求一个updateToken即可,其他则直接排队,等待第一个拿到后,直接使用
request1.js代码
let isRefreshing = true; // 请求锁
let pendings = []; // 请求列表
const pathArr = ['pages/buy-goods/index']; // 不需要登录的路径
const baseUrl = "http://192.168.0.112:9999";// 基础路径
function request({method, url, data, options = {
needLogin: true
}}) {
const token = wx.getStorageSync('tokenInfo')
const pages = getCurrentPages();
const router = pages[pages.length - 1]['route']; // 当前路由
if (pathArr.includes(router)) options.needLogin = false; // 当前路径是否需要登录
return new Promise((resolve, reject) => {
// 需要登录 但是 token不存在 跳转登录
if (!token && options.needLogin) {
wx.redirectTo({
url: '/pages/login/login',
})
return
}
wx.showNavigationBarLoading();
wx.showLoading({
title: '数据加载中...',
mask: true
})
// 请求主体
wx.request({
url: baseUrl + url,
header:{
Authorization:token.access_token
},
method,
data,
success(res) {
let code = res.data.code
if (code == '9898') {
resolve(res.data)
} else if (code == '200') {
if (isRefreshing) {
updateToken();
isRefreshing = false;
pendings.push(() => {
resolve(request({method, url, data, options}))
})
}
} else {
resolve(res.data);
}
},
fail(err) {
reject(err);
},
complete() {
wx.hideNavigationBarLoading();
wx.hideLoading();
}
})
})
}
// 刷新token
function updateToken() {
const token = wx.getStorageSync('tokenInfo');
const userId = token.user_id;
const refreshToken = token.refresh_token;
wx.request({
url: baseUrl + '/user/refreshToken',
method: 'POST',
data: {
userId: userId,
refreshToken: refreshToken
},
success(res) {
let code = res.data.code
if (code == '200') {
wx.setStorageSync('tokenInfo', {
access_token: res.data.data.accessToken,
refresh_token: res.data.data.refreshToken,
user_id: res.data.data.userId,
});
pendings.map((callback) => {
callback();
})
isRefreshing = true;
} else {
toLogin();
}
}
})
}
// 前往登录页面 清空状态
function toLogin() {
wx.showToast({
title: '登录失效,请重新登录',
icon: "none",
success: () => {
setTimeout(() => {
wx.redirectTo({
url: '/pages/login/login',
})
pendings = [];
isRefreshing = true;
}, 1200);
}
})
}
module.exports = {
request
};
业务js
import {
request
} from '../../request/request1.js';
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
const orderId = options.orderId;
this.queryOrderQuoteList(orderId);
},
async queryOrderQuoteList(orderId){
const res = await request({
method:"POST",
url:"/order-quote/queryOrderQuoteList",
data:{
orderId: orderId,
pageNum: 1,
pageSize: 10
}
});
console.log(res);
}
})