维护你的请求队列,处理token异常_晴枙_前端开发者

前言

网络请求是开发中最基础也是最核心的需求,封装一个稳定且可用性高的请求也显得尤为重要。通常封装的内容除了入参之外,更多的是请求中的异常处理。本文分享下我在处理 token 异常方面的做法,通过维护请求队列,实现重发请求,减少 token 重复请求。

tokentoken

公共请求方法

下面以封装微信小程序请求作为例子,这是一个基础的公共请求:

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
    })
  })
}

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 存储到本地中

getTokentoken

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)
  }
}

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

tokengetTokenresolve

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
    })
  })
}

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

getTokenwxLogin

维护请求队列

理想的情况是:token 过期后,发起一个 getToken 请求。每当有请求进来,将它存入队列中,等待 getToken 完成,执行队列中的所有请求。

tokengetTokengetToken

这样我们需要定义请求队列 qeueutoken 请求的标识 isTokening,还有加入队列方法 pushQeueu 和执行队列方法 execQeueu

qeueutokenisTokeningpushQeueuexecQeueu

{
  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
      }
    })
  }
}

{
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
    })
  })
}

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

getTokenisTokeningtruegetToken

处理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()
    }
  }
}

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 异常的做法,如果你有更好的做法或建议,欢迎交流~

» 本文来自:前端开发者 » 《维护你的请求队列,处理token异常_晴枙_前端开发者》
» 本文链接地址:https://www.rokub.com/73150.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!