0
点赞
收藏
分享

微信扫一扫

前端刷新token,重新发起请求,异步并发请求处理。

路西法阁下 2021-09-19 阅读 48

token过期后,需要前端携带旧的token去请求后端接口置换新的token

实现思路:协定错误码XXX,在响应拦截中拦截,发起刷新token请求,刷新完毕调用axios实例重新发起中断的请求。
我这里用的是401状态码
        //刷新token
        case 401:
        //发起刷新token的请求
            await getToken({}).then((res) => 
              if (res.code == 200) {//刷新成功 
                cookies.set("token", res.data); //替换新的token
                service(response.config);//重新发起由于token过期中断的请求
              } else {
                //刷新失败 重新登录
                if (doms2 == undefined) {
                  Message.error({
                    message: "登录失效,请重新登录",
                  });
                }
                //清除登录状态
                cookies.remove("infor");
                cookies.remove("token");
              }
            });

当token过期,一个页面异步同时发出多个请求时,多接口都携带旧token去请求,
不同时间返回401错误,挨个都去置换token造成被多次刷新异常。

解决思路:
  • 草根方案:

使用async、await函数把页面所有异步请求变成同步,等待上一个执行完毕再执行下一个请求。

  • 较完美方案:

在响应拦截器中第一个返回401执行刷新token的操作时候,设置一个正在更新token的状态,
其他的异步并发的请求返回401被拦截下来就不要去重复的执行更新token,用函数的形式暂存起来,
等待更新完毕再一起重新发起。

let isRefreshing = false;  // 定义一个是否正在刷新token的标记
let retryRequests = [];// 定义一个空数组,承载请求队列
        //刷新token
        case 401:
          //判断是否正在更新token
          if (!isRefreshing) {
            isRefreshing = true; //更新状态
            //发起刷新token
            await getToken({}).then((res) => {
              if (res.code == 200) {
                cookies.set("token", res.data); //刷新成功
                //遍历缓存队列 发起请求 传入最新token
                retryRequests.forEach((cb) => cb(res.data));
                // 重试完清空这个队列
                retryRequests = [];
                service(response.config);
              } else {
                //刷新失败 重新登录
                if (doms2 == undefined) {
                  Message.error({
                    message: "登录失效,请重新登录",
                  });
                }
                //清除登录状态
                cookies.remove("infor");
                cookies.remove("token");
              }
            });
            // 正在刷新token,返回一个未执行resolve的promise
          } else {
             //这里的Promise里并没有调用resolve()去改变状态,而是直接push一个函数方法到数组
              //这样就可以把请求暂存起来,等待上面刷新token请求成功后,遍历 retryRequests数组
             //把新的token通过函数传参方式传入  调用方法执行重新请求
            return new Promise((resolve) => {
              // 将resolve放进队列,用一个函数形式来保存,等token刷新后调用执行
              retryRequests.push((token) => {
                response.config.headers.Authorization = token;
                resolve(service(response.config));
              });
            });
          }
          break;

以上已经实现异步请求并发时,暂存错误队列,等待token刷新成功后统一重新发起请求的问题。
有描述不清楚或者错误的地方欢迎提出指正。

举报

相关推荐

0 条评论