preface

Network request is the most basic and core requirement in development, and it is particularly important to encapsulate a stable and high availability request. What is usually encapsulated is more exception handling in the request than just input arguments. This article will share my approach in handling token exceptions. By maintaining the request queue, I can realize resending requests and reduce token repeated requests.

Common request method

The following is an example of encapsulating a wechat applets request, which is a basic common 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 expires}},fail: reject
    })
  })
}
Copy the code

The token expires and resends the request

The getToken method internally 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)
  }
}
Copy the code

When the token expires, after waiting for getToken, send the request again and 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
    })
  })
}
Copy the code

This may seem fine, but since there is no internal limit to processing, n getToken requests are made for n requests. This is certainly not what we want, as the following repeated wxLogin:

Maintain request queue

Ideally, after the token expires, a getToken request is made. Whenever a request comes in, it is queued up and waited for getToken to complete, executing all requests in the queue.

So we need to define the isTokening of the qEUEU request queue and the token request identifier, as well as the queueing method pushQeueu and the execution of the queueing 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 the queue after executing the task
      if(index === this.qeueu.length- 1) {this.qeueu.length = 0}}}})Copy the code

The processing 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
    })
  })
}
Copy the code

After initiating the getToken request, set isTokening to true to indicate that the request is in progress. When additional requests come in, the getToken is not sent again.

Error handling getToken

GetToken in the event of an error, we should catch the error, discontinue 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()
    }
  }
}
Copy the code

Write in the last

The above is my way of dealing with token exception, if you have better way or suggestion, welcome to exchange ~