簡介:
在微信小程序開發(fā)過程中,網(wǎng)絡(luò)請求是開發(fā)中最基礎(chǔ)也是最核心的需求,封裝一個(gè)穩(wěn)定且可用性高的請求也顯得尤為重要。通常封裝的內(nèi)容除了入?yún)⒅猓嗟氖钦埱笾械漠惓L幚怼T谔幚?token 異常方面的做法,通過維護(hù)請求隊(duì)列,實(shí)現(xiàn)重發(fā)請求,減少 token 重復(fù)請求。
步驟:
- 正常業(yè)務(wù)請求
- 檢查該請求地址是否需要登錄后訪問,如果不需要,則直接訪問,該請求結(jié)束
- 如果需要,則判斷緩存Token是否存在,如果不存在,則直接跳轉(zhuǎn)登錄,如果存在,進(jìn)入步驟4
- 請求后端接口,請求token未過期,則正常返回業(yè)務(wù)數(shù)據(jù),如果請求token過期,則進(jìn)入步驟5
- 調(diào)用Token刷新接口,刷新token過期,則直接跳轉(zhuǎn)登錄
- 刷新token沒有過期,則獲取token,并存入緩存 進(jìn)入步驟7
- 在客戶無感知(無痛)情況下繼續(xù)請求最初的業(yè)務(wù)請求,將結(jié)果返回
需要注意:請求如果沒有限制處理,有多個(gè)請求同時(shí)到達(dá),就會(huì)發(fā)起多個(gè) updateToken 請求,其實(shí)我們并不想這樣,只需要請求一個(gè)updateToken即可,其他則直接排隊(duì),等待第一個(gè)拿到后,直接使用
request1.js代碼
let isRefreshing = true; // 請求鎖
let pendings = []; // 請求列表
const pathArr = ['pages/buy-goods/index']; // 不需要登錄的路徑
const baseUrl = "http://192.168.0.112:9999";// 基礎(chǔ)路徑
function request({method, url, data, options = {
needLogin: true
}}) {
const token = wx.getStorageSync('tokenInfo')
const pages = getCurrentPages();
const router = pages[pages.length - 1]['route']; // 當(dāng)前路由
if (pathArr.includes(router)) options.needLogin = false; // 當(dāng)前路徑是否需要登錄
return new Promise((resolve, reject) => {
// 需要登錄 但是 token不存在 跳轉(zhuǎn)登錄
if (!token && options.needLogin) {
wx.redirectTo({
url: '/pages/login/login',
})
return
}
wx.showNavigationBarLoading();
wx.showLoading({
title: '數(shù)據(jù)加載中...',
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();
}
}
})
}
// 前往登錄頁面 清空狀態(tài)
function toLogin() {
wx.showToast({
title: '登錄失效,請重新登錄',
icon: "none",
success: () => {
setTimeout(() => {
wx.redirectTo({
url: '/pages/login/login',
})
pendings = [];
isRefreshing = true;
}, 1200);
}
})
}
module.exports = {
request
};
業(yè)務(wù)js
import {
request
} from '../../request/request1.js';
Page({
/**
* 頁面的初始數(shù)據(jù)
*/
data: {
},
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
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);
}
})
效果
正常業(yè)務(wù)請求
刷新token
繼續(xù)請求業(yè)務(wù)