維護你的請求隊列,處理token異常
- 2020 年 4 月 4 日
- 筆記
前言
網路請求是開發中最基礎也是最核心的需求,封裝一個穩定且可用性高的請求也顯得尤為重要。通常封裝的內容除了入參之外,更多的是請求中的異常處理。本文分享下我在處理 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 異常的做法,如果你有更好的做法或建議,歡迎交流~