token无痛刷新

本文探讨了在网络安全背景下,前端如何处理网络请求中的Token过期问题。主要涉及在响应拦截器中重新发起请求、控制并发请求以及在拦截器中获取新Token的策略。通过axios拦截器和Promise的管理,实现了Token过期后的平滑处理,确保用户体验和系统稳定性。
摘要由CSDN通过智能技术生成

1.技术背景

在追求网络安全的大环境下,前端在处理网络请求的安全性控制有了更高的需求,回归问题的本质,处理token过期问题。

1.1 token过期需要解决的几个痛点

i. 怎么在响应式拦截器中重新发起请求
ii. 怎么处理token过期后大量请求并发
iii. token过期后在响应拦截器中怎么重新获取token

2.技术应用

在解决上面提到的三个痛点之前,我们需要着重了解两个知识点:

  1. axios拦截器
  2. promise的三种状态success(resolve) fail(reject) pending

这边我不着重讲述,相信大家已经能熟练掌握这两个知识点。
axios响应拦截器中,提取response.config这个属性中包含了所有请求相关的参数,所以我们可以使用axios(response.config)重新发起请求。
promise大家最常用的是成功态和失败态,但很多时候我们忽略了他的pending态,当Promise对象的resolve方法未被调用的情况下他始终处于pending (等待)状态。

3.技术实现

3.1响应式拦截器中获取token并重新发起请求

首先我们来解决第一个痛点——怎么在响应式拦截器中重新发起请求 ?

miniAxios.interceptors.response.use(
  async response => {
    const config = response.config as IConfig;
    const resData = response.data;
    if (resData?.code === REQUEST_SUCCESS_CODE) {
      // 请求成功
      return Promise.resolve(resData?.data);
    }
    
    // token过期
    if (resData.subCode === 'user.token.expired') {
        // 重新请求token
        const authCode = await getAuthCodePromise();
        const [err, res] = await authBase(authCode);
        alipayUserId = res?.alipayUserId || '';
        userToken = res?.userToken || '';
        config.headers.userToken = userToken;
        // 重置baseUrl  特别注意:如果不重置会出现/api/api
        config.baseURL = '';
        // 重新请求
        return miniAxios(config);
      
    }
    // 错误处理
    return Promise.reject(resData);
  },
  err => {
  },
);

3.2 控制处理token过期后大量请求并发

步骤一:我们需要在请求拦截器第一个返回token过期的接口去处理
步骤二:拦截后面返回的所有请求,防止大量失效接口返回,同时通过promise等待队列存储后面的所有请求
步骤三:重新获取token,等新token返回,释放promise等待队列中所有的请求(即重新发起请求)


let userToken = '';
// token刷新标识位
let isRefreshing = false;
// 请求等待队列
const requestList = [];
miniAxios.interceptors.response.use(
  async response => {
    // 获取请求数据
    const config = response.config as IConfig;
    if (config.loading) {
      closeLoading();
    }
    // 成功
    const resData = response.data;
    if (resData?.code === REQUEST_SUCCESS_CODE) {
      // 请求成功
      return Promise.resolve(resData?.data);
    }

    // token过期
    if (resData.subCode === 'user.token.expired') {
      if (!isRefreshing) {
        // 不在刷新
        // 刷新标识位置为true
        isRefreshing = true;
        // 请求token
        const authCode = await getAuthCodePromise();
        const [err, res] = await authBase(authCode);
        alipayUserId = res?.alipayUserId || '';
        userToken = res?.userToken || '';
        config.headers.userToken = userToken;
        // 重置baseUrl 特别注意:如果不重置会出现/api/api
        config.baseURL = '';
        // 拿到新token,resolve所有请求(释放所有promise)
        requestList.forEach(cb => cb(userToken));
        // 刷新结束
        isRefreshing = false;
        // 重新请求
        return miniAxios(config);
      }
      // 将所有请求暂存与请求队列中,利用promise的pending状态
      // 核心代码逻辑: 只要promise中的resolve没有调用,他会一直处于pending状态
      return new Promise(resolve => {
        // 加入请求队列
        requestList.push(token => {
          // 重置baseUrl 特别注意:如果不重置会出现/api/api
          config.baseURL = '';
          // 更新token
          config.headers.userToken = token;
          // 将promise.resolve塞入队列
          resolve(miniAxios(config));
        });
      });
    }
    // 错误处理
    return Promise.reject(resData);
  },
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值