关于python:某课构建数据工程师能力模型实战八大企业级项目wu密

download:百度网盘

需要

对于须要前端实现无痛刷新Token,无非就两种:

申请前判断Token是否过期,过期则刷新
申请后依据返回状态判断是否过期,过期则刷新

解决逻辑
实现起来也没多大差异,只是判断的地位不一样,外围原理都一样:

判断Token是否过期

没过期则失常解决
过期则发动刷新Token的申请

拿到新的Token保留
从新发送Token过期这段时间内发动的申请

重点:

放弃Token过期这段时间发动申请状态(不能进入失败回调)
把刷新Token后从新发送申请的响应数据返回到对应的调用者

实现

创立一个flag isRefreshing 来判断是否刷新中
创立一个数组队列retryRequests来保留须要从新发动的申请
判断到Token过期

isRefreshing = false 的状况下 发动刷新Token的申请

刷新Token后遍历执行队列retryRequests

isRefreshing = true 示意正在刷新Token,返回一个Pending状态的Promise,并把申请信息保留到队列retryRequests中

import axios from “axios”;
import Store from “@/store”;
import Router from “@/router”;
import { Message } from “element-ui”;
import UserUtil from “@/utils/user”;

// 创立实例
const Instance = axios.create();
Instance.defaults.baseURL = “/api”;
Instance.defaults.headers.post[“Content-Type”] = “application/json”;
Instance.defaults.headers.post[“Accept”] = “application/json”;

// 定义一个flag 判断是否刷新Token中
let isRefreshing = false;
// 保留须要从新发动申请的队列
let retryRequests = [];

// 申请拦挡
Instance.interceptors.request.use(async function(config) {
Store.commit(“startLoading”);
const userInfo = UserUtil.getLocalInfo();
if (userInfo) {

//业务须要把Token信息放在 params 外面,一般来说都是放在 headers外面
config.params = Object.assign(config.params ? config.params : {}, {
  appkey: userInfo.AppKey,
  token: userInfo.Token
});

}
return config;
});

// 响应拦挡
Instance.interceptors.response.use(
async function(response) {

Store.commit("finishLoading");
const res = response.data;
if (res.errcode == 0) {
  return Promise.resolve(res);
} else if (
  res.errcode == 30001 ||
  res.errcode == 40001 ||
  res.errcode == 42001 ||
  res.errcode == 40014
) {
// 须要刷新Token 的状态 30001 40001 42001 40014
// 拿到本次申请的配置
  let config = response.config;
//   进入登录页面的不做刷新Token 解决
  if (Router.currentRoute.path !== "/login") {
    if (!isRefreshing) {
        // 扭转flag状态,示意正在刷新Token中
      isRefreshing = true;
    //   刷新Token
      return Store.dispatch("user/refreshToken")
        .then(res => {
        // 设置刷新后的Token
          config.params.token = res.Token;
          config.params.appkey = res.AppKey;
        //   遍历执行须要从新发动申请的队列
          retryRequests.forEach(cb => cb(res));
        //   清空队列
          retryRequests = [];
          return Instance.request(config);
        })
        .catch(() => {
          retryRequests = [];
          Message.error("主动登录失败,请从新登录");
            const code = Store.state.user.info.CustomerCode || "";
            // 刷新Token 失败 清空缓存的用户信息 并调整到登录页面
            Store.dispatch("user/logout");
            Router.replace({
              path: "/login",
              query: { redirect: Router.currentRoute.fullPath, code: code }
            });
        })
        .finally(() => {
            // 申请实现后重置flag
          isRefreshing = false;
        });
    } else {
      // 正在刷新token,返回一个未执行resolve的promise
      // 把promise 的resolve 保留到队列的回调外面,期待刷新Token后调用
      // 原调用者会处于期待状态直到 队列从新发动申请,再把响应返回,以达到用户无感知的目标(无痛刷新)
      return new Promise(resolve => {
        // 将resolve放进队列,用一个函数模式来保留,等token刷新后间接执行
        retryRequests.push(info => {
            // 将新的Token从新赋值
          config.params.token = info.Token;
          config.params.appkey = info.AppKey;
          resolve(Instance.request(config));
        });
      });
    }
  }
  return new Promise(() => {});
} else {
  return Promise.reject(res);
}

},
function(error) {

let err = {};
if (error.response) {
  err.errcode = error.response.status;
  err.errmsg = error.response.statusText;
} else {
  err.errcode = -1;
  err.errmsg = error.message;
}
Store.commit("finishLoading");
return Promise.reject(err);

}
);

export default Instance;

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理