前端实现token无感刷新

  1. 一种前端处理 根据后台返的时间来刷新token(优点: 在请求前拦截,能节省请求。缺点: 需要后端额外提供一个token过期时间的字段;使用了本地时间判断,若本地时间被篡改,特别是本地时间比服务器时间慢时,拦截会失败。不采用)
  2. 不在请求前拦截,而是拦截返回后的数据。先发起请求,接口返回过期后,先刷新token (优点:不需额外的token过期字段,不需判断时间。缺点 会消耗多一次请求) 采用
    凡是用前端直接处理的一般都不安全
import axios from "axios";
import { Message } from "element-ui";
import router from "@/router/index";
// 根据开发环境取请求域名(vite)
let axiosBaseUrl = import.meta.env.VITE_BASE_URL;
let isRefreshing = false; // 定义一个是否正在刷新token的标记
let retryRequests = []; // 定义一个空数组,承载请求队列
//  创建一个实例
const service = axios.create({
  baseURL: axiosBaseUrl,
  timeout: 10000,
});
// 请求拦截
service.interceptors.request.use(
  (config) => {
    if (localStorage.getItem("access_token")) {
      //  判断token是否存在,存在即加上token
      let token = localStorage.getItem("access_token");
      config.headers["Authorization"] = "bearer " + token;
    }
    // 加公参
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);
// 响应拦截
service.interceptors.response.use(
  (response) => {
    // 状态码和后台确定的
    if (response.data.code == 1002) {
      //判断是否正在更新token
      console.log("isRefreshing  是否更新", isRefreshing);
      if (!isRefreshing) {
        isRefreshing = true; //更新状态
        refreshTokenFun();
      }
      //这里的Promise里并没有调用resolve()去改变状态,而是直接push一个函数方法到数组
      //这样就可以把请求暂存起来,等待上面刷新token请求成功后,遍历 retryRequests数组
      // 解决返回值返回undefiend
      return new Promise((resolve) => {
        // 将resolve放进队列,用一个函数形式来保存,等token刷新后调用执行
        retryRequests.push(() => {
          resolve(service(response.config));
        });
      });
    } else if (response.data.code == 1007) {
      Message.error("登录失效");
      router.replace({
        path: "/login",
      });
    }
    return response;
  },
  (error) => {
    Message.error("网络不佳,请求超时!");
    return Promise.reject(error);
  }
);
// 刷新token
function refreshTokenFun() {
  // 根据自己项目来取token
  let token = localStorage.getItem("access_token");
  // 刷新token
  axios
    .get(axiosBaseUrl + "/oss/v1/refresh", {
      headers: {
        Authorization: "bearer " + token,
      },
    })
    .then(function(res) {
      // 根据自己项目来判断请求成功储存新的token
      let resData = res.data;
      if (resData.code == 0) {
        localStorage.setItem("access_token", resData.data.access_token);
        // 刷新完毕继续请求数据
        retryRequests.forEach((cb) => cb());
        // 重试完清空这个队列
        retryRequests = [];
        isRefreshing = false;
      } else if (resData.code == 1007) {
        //   也可以根据自己项目状态来跳login
        router.replace({
          path: "/login",
        });
      }
    })
    .catch((e) => {
      console.log("报错信息", e);
    })
    .finally(() => {
      // 更新刷新状态  以免下次token刷新不调用
      isRefreshing = false;
    });
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值