维护你的请求队列,处理token异常
前言
网络请求是开发中最基础也是最核心的需求,封装一个稳定且可用性高的请求也显得尤为重要。通常封装的内容除了入参之外,更多的是请求中的异常处理。本文分享下我在处理 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 异常的做法,如果你有更好的做法或建议,欢迎交流~
维护你的请求队列,处理token异常的更多相关文章
- Android-Volley网络通信框架(二次封装数据请求和图片请求(包含处理请求队列和图片缓存))
		1.回想 上篇 使用 Volley 的 JsonObjectRequest 和 ImageLoader 写了 电影列表的样例 2.重点 (1)封装Volley 内部 请求 类(请求队列,数据请求,图片 ... 
- 编写简单的ramdisk(有请求队列)
		前言 前面用无请求队列实现的ramdisk的驱动程序虽然申请了请求队列,但实际上没用上,因为ramdisk不像实际的磁盘访问速度慢需要缓存,ramdisk之间使用内存空间,所以就没用请求队列了.本文将 ... 
- 编写简单的ramdisk(无请求队列)
		最近在研究块设备驱动的编写,看了赵磊大牛的<写一个块设备驱动>,受益匪浅,虽然能看懂里面说的,但动手写写代码还是能加深理解的,下面实现的ramdisk写的很简单,如果有错误,欢迎大牛们指正 ... 
- ASP.Net的工作线程与请求队列
		当 ASP.NET 接收针对页的请求时,它从线程池中提取一个线程并将请求分配给该线程. 一个普通的(或同步的)页在该请求期间保留线程,从而防止该线程用于处理其他请求.如果一个同步请求成为 I/O bo ... 
- mvc 使用预置队列类型存储异常对象
		using PaiXie.Utils; using System; using System.Collections.Generic; using System.Linq; using System. ... 
- springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。为了区别不同的异常通常根据异常类型自定义异常类,这里我们创建一个自定义系统异常,如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。
		springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑. 1.1 异常处理思路 系统中异常包括两类:预期异常和运行时异常RuntimeEx ... 
- 统一处理jquery ajax请求过程中的异常错误信息的机制
		当jQuery ajax向服务器发送请求,服务器发生异常,比如:400.403.404.500等异常,服务器将异常响应给客户端,此时的ajax可以获取异常信息并进行处理,但此时我们一般是跳转到与异常编 ... 
- axios中为所有请求带上Token头
		axios中为所有请求带上Token头 https://www.imooc.com/article/27751 
- golang API 请求队列
		概要 实现思路 使用方法 启动队列服务 使用队列服务 概要 在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP ... 
随机推荐
- 菜鸟系列 Golang 实战 Leetcode —— 面试题24. 反转链表
			定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点. 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3- ... 
- 手把手教你轻松使用数据可视化BI软件创建某疾病监控数据大屏
			灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件. 本文以某疾病监控数据大屏为例为 ... 
- springboot自动装配原理回顾、配置文件分析
			配置文件 spring boot官方文档 官方外部配置文件说明参考文档 自动配置原理分析 1. SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfigurat ... 
- Xcode辅助工具之热重载插件利器
			该博客首发于github.io 2018-06-13 13:43:44 文章最新修改于: 2019-03-31 13:47:20 昨天刚刚看完iOSTips微信公众号推送的文章, Injection: ... 
- ts文件的编译和运行
			hello.ts代码 function sayHello(person: string): string { return 'Hello, ' + person; } let user = 'Tom' ... 
- 从0开始搭建一个阿里云java部署环境
			一.购买服务器 https://www.aliyun.com/daily-act/ecs/activity_selection?spm=5176.8112568.738194.8.674c9ed53Y ... 
- HTML5  基础知识(1)——基本标签
			## HTML**概念**:是最基础的网页开发语言(Hyper Text Markup Langage 超文本标记语言) > 1.超文本:超文本是用超链接的方式i,将各种不同空间的文字组织在一起 ... 
- HDFS 客户端读写操作详情
			1. 写操作 客户端向namenode发起上传请求 namenode检查datanode是否已经存有该文件,并且检查客户端的权限 确认可以上传后,根据文件块数返回datanode栈 注:namenod ... 
- MFC Camera 摄像头预览 拍照
			windows 上开发摄像头程序,比较容易的方式是 OpenCV ,几行代码就能显示出来,但是简单的容易搞,有点难度定制化需求的就不这么容易了.所以说还是要从,最基础的 DirectShow 开始搞起 ... 
- Falsk 路由简析
			添加路由 我们熟知添加路由的方式是装饰器: @app.route('/') def hello_world(): return 'Hello World!' #访问web得到 'Hello World ... 
