前言 網路請求是開發中最基礎也是最核心的需求,封裝一個穩定且可用性高的請求也顯得尤為重要。通常封裝的內容除了入參之外,更多的是請求中的異常處理。本文分享下我在處理 異常方面的做法,通過維護請求隊列,實現重發請求,減少 重覆請求。 公共請求方法 下麵以封裝微信小程式請求作為例子,這是一個基礎的公共請求 ...
前言
網路請求是開發中最基礎也是最核心的需求,封裝一個穩定且可用性高的請求也顯得尤為重要。通常封裝的內容除了入參之外,更多的是請求中的異常處理。本文分享下我在處理 token
異常方面的做法,通過維護請求隊列,實現重發請求,減少 token
重覆請求。
公共請求方法
下麵以封裝微信小程式請求作為例子,這是一個基礎的公共請求:
common({ baseUrl = this.baseUrl, method, url, data, header }) {
return new Promise((resolve, reject) => {
let token = wx.$utils.getStorageToken()
wx.request({
method,
url: baseUrl + url,
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
token,
...header
},
success: (res) => {
if (res.data.code == 0 || res.data.code == 500) { // 失敗
reject(res.data)
}
if (res.data.code == 1) { // 成功
resolve(res.data)
}
if (res.data.code == -1) { // token過期
// token過期處理
}
},
fail: reject
})
})
}
token過期重發請求
getToken
方法內部會將 token
存儲到本地中
success: (res) => {
res = res.data
if (res.code == 0) {
reject(res.msg)
}
if (res.code == 1) {
wx.setStorageSync('loginInfo', res.data)
resolve(res.data.token)
}
}
當 token
過期,在等待 getToken
後,再次發送請求,將結果 resolve
common({ baseUrl = this.baseUrl, method, url, data, header }) {
return new Promise((resolve, reject) => {
let token = wx.$utils.getStorageToken()
wx.request({
method,
url: baseUrl + url,
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
token,
...header
},
success: async (res) => {
if (res.data.code == 0 || res.data.code == 500) {
reject(res.data)
}
if (res.data.code == 1) {
resolve(res.data)
}
if (res.data.code == -1) {
+ await this.getToken()
+ this.common({ baseUrl, method, url, data, header })
+ .then(resolve)
+ .catch(reject)
}
},
fail: reject
})
})
}
這樣看起來好像沒什麼問題,但由於內部沒有限制處理,有 n 個請求就會發起 n 個 getToken
請求。這當然不是我們想要的,就像下麵這樣重覆發起了兩次 wxLogin
:
維護請求隊列
理想的情況是:token
過期後,發起一個 getToken
請求。每當有請求進來,將它存入隊列中,等待 getToken
完成,執行隊列中的所有請求。
這樣我們需要定義請求隊列 qeueu
和token
請求的標識 isTokening
,還有加入隊列方法 pushQeueu
和執行隊列方法 execQeueu
。
{
qeueu: [],
isTokening: false,
pushQeueu({ method, url, data, header, resolve, reject }){
this.qeueu.push({
data: {
method, url, data, header
},
resolve,
reject,
request: (data)=> this.common(data)
})
},
execQeueu(){
this.qeueu.forEach((item, index) => {
item.request(item.data)
.then(item.resolve)
.catch(item.reject)
// 執行完任務後 清空隊列
if(index === this.qeueu.length-1){
this.qeueu.length = 0
}
})
}
}
處理如下:
common({ baseUrl = this.baseUrl, method, url, data, header }) {
return new Promise((resolve, reject) => {
let token = wx.$utils.getStorageToken()
wx.request({
method,
url: baseUrl + url,
data,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
token,
...header
},
success: async (res) => {
if (res.data.code == 0 || res.data.code == 500) {
reject(res.data)
}
if (res.data.code == 1) {
resolve(res.data)
}
if (res.data.code == -1) {
+ this.pushQeueu({ method, url, data, header, resolve, reject })
+ if(this.isTokening === false){
+ this.isTokening = true
+ await this.getToken()
+ this.isTokening = false
+ this.execQeueu()
+ }
}
},
fail: reject
})
})
}
發起 getToken
請求後,將 isTokening
置為 true
表示正在請求中。當再有請求進入時,則不會再重覆發送 getToken
。
處理getToken錯誤
getToken
在發生錯誤時,我們應當捕獲錯誤,不繼續執行請求隊列並清空隊列
if (res.data.code == -1) {
this.pushQeueu({ method, url, data, header, resolve })
if(this.isTokening === false){
this.isTokening = true
let err = await this.getToken().then(res => null).catch(err => err)
if(err){
this.qeueu.length = 0
console.error(err)
}else{
this.isTokening = false
this.execQeueu()
}
}
}
寫在最後
以上是我在處理 token 異常的做法,如果你有更好的做法或建議,歡迎交流~