Preface
Network request is the most basic and core requirement in development. It is very important to encapsulate a stable and high availability request. In addition to the input parameters, the encapsulated content is more about exception handling in the request. This article shares my practice in dealing with token exceptions. By maintaining the request queue, I can resend the request and reduce the repeated request of token.
Public request method
The following is an example of encapsulating wechat applet request, which is a basic public request:
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) { // fail reject(res.data) } if (res.data.code == 1) { // Success resolve(res.data) } if (res.data.code == -1) { // token expired // token expiration processing } }, fail: reject }) }) }
token expired resend request
The internal getToken method stores the token locally
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) } }
When the token expires, after waiting for getToken, send the request again to resolve the result
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 }) }) }
It seems that there is no problem in this way, but since there is no internal restriction on processing, n requests will initiate n getToken requests. Of course, this is not what we want. We repeatedly launched wxLogin twice as follows:
Maintenance request queue
Ideally, after the token expires, a getToken request is initiated. Every time a request comes in, put it in the queue, wait for the getToken to complete, and execute all the requests in the queue.
In this way, we need to define the request queue qeueu and the token request ID isTokening, as well as the join queue method pushQeueu and the execute queue method 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) // Clear queue after task execution if(index === this.qeueu.length-1){ this.qeueu.length = 0 } }) } }
The treatment is as follows:
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 }) }) }
After the getToken request is initiated, setting isTokening to true indicates that the request is in progress. When another request enters, the getToken will not be sent repeatedly.
Handling getToken errors
getToken when an error occurs, we should catch the error, do not continue to execute the request queue and empty the queue
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() } } }
Written in the end
The above is what I am doing to handle token exceptions. If you have better practices or suggestions, please contact me~