如何让所有请求等待token回来

805 阅读2分钟

问题:所有请求等待token

很多项目登陆使用的是前端传token,后端认证的方式,这就需要前端登陆后需要请求包括token等等的用户信息,将token放置到所有请求的header中,每一次请求都需要将token发到后台去。

这时候就需要进行处理,如何让其他所有请求,都能等待获取token等用户信息的这次请求之后再请求呢?

有很多种方法可以实现,例如,在vue项目中,我们可以在App.vue中加入一个flag,控制路页面组件的显示,在App.vue中获取token,当这个请求完成前,子页面都不显示,,自然里面的接口都不会调用,这个请求完成后,再将页面显示出来。

这样做的好处是方便,可是这就给用户人为增加了一段白屏时间,毕竟我们的网页有部份内容也不需要请求接口也可以展示。

解决:使用拦截器和promise

解决的思路是设立一个flag,专门识别获取token的请求是否已经完成,在这个请求完成前,其他请求都需要拦截保存下来不发送,等待获取token的请求回来后,再将保存的请求全部执行。

为了在请求接口上动手脚,我们需要用到axios的拦截器,而请求的拦截与保存我们需要用到promise,只要他不执行resolve,就是永远处于等待着的状态,直接上代码。

// 请求获取token接口的标记,0未请求,1正在请求,2已请求
let isGotToken = 0;
// 请求队列
let requests = [];

let token = ''
// 请求拦截器
axios.interceptors.request.use(
   async config => {
    if (isGotToken == 2 || config.url.includes("/get/token")) {
      // info已经请求或者正在请求token接口
      token && (config.headers.authorization = token);
      return config
    } else {
    	//获取token接口没有请求过
      if (!isGotToken) {
        // 正在获取
        isGotToken = 1
        try {
          //获取token和用户信息的请求,保存到vuex中
          token = await getToken()
        } catch (e) {

        }

        isGotToken = 2
        token && (config.headers.authorization = token);
        // 把原来保存的请求重新执行,记得把刚刚请求到的token传进去
        requests.forEach((cb) => cb(token));
        requests = [];

        // 以下为正在拦截的请求,没有被队列保存下来,所以重新return出去单独处理        
        return config
      } else {
        // info没有请求,保存所有请求等待token回复,只要没有执行resolve就一直在等待
        return new Promise(resolve => {
          requests.push((token) => {
          token && (config.headers.authorization = token);
            resolve(config);
          })
        });
    }
    }
  }

当然可以把token本身当作是否请求过token的flag, 下面是前后的对比:

改造之前:

改造之后:

所有的接口都会等待info请求(获取token)返回后再开始请求。