用axios封装无感刷新token

  • 1. 封装接口请求
  • 2.分离刷新token的js

1. 封装接口请求

request.js

import axios from 'axios'
import { apiUrl } from '@/config/global_config'
import refreshToken from './refreshToken'

//前缀
const service = axios.create({
  baseURL: apiUrl,
  timeout: 5000 // 请求超时时间
})

//请求
service.interceptors.request.use(
  config => {
    return config
  },
  error => {
    console.log(error)
    return Promise.reject(error)
  }
)

//响应
service.interceptors.response.use(
  response => {
    const data = response.data
    if (data.code === 200) {
      return Promise.resolve(data)
    } if (data.code === 401) {
      refreshToken(response)
    } else {
      let err = {}
      let messInfo = data.message ? err.info + ' ' + data.message : err.info
      return Promise.reject(new Error(messInfo || 'Error'))
    }
  },
  err => {
    console.log('响应错误:' + err)
    return Promise.reject(err) //请求错误时,直接结束
  }
)

// 封装通用的接口调用方法
export default (options) => {
  return service({
    method: options.method || 'GET',
    url: options.url,
    // ES6规则:对象的key可以是动态的变量
    [options.method.toUpperCase() === 'GET' ? 'params' : 'data']: options.data
  })
}

2.分离刷新token的js

refreshToken.js

import { useRouter } from 'vue-router';
import request from './request';
import { ElMessage } from 'element-plus'

const MAX_ERROR_COUNT = 5; //最大请球次数
let currentCount = 0; //当前请求了多少次
const queue = []; //把阻塞的请求储存到数组里一次请求玩
let isRefresh = false;

const { router } = useRouter()
export default async function refreshToken(error) {
  // 退出登录
  const logout = () => {
    ElMessage.error('身份过期,请重新登录')

    router.replace('/login')
    // 清空数据 token的数据  
    // Session.clear();
    localStorage.clear()

    return Promise.reject(error);
  };
  if (error.config.url?.includes('refresh')) {
    // 如果url中包含refresh 退出登录
    logout();
  }
  const refresh = localStorage.getItem('refresh') ?? null;

  const { config } = error;
  if (!refresh) {  //如果没找到替换的refreshtoken退出登录
    logout();
  }
  // 判断当前是否为刷新状态中(防止多个请求导致多次调refresh接口)
  if (!isRefresh) {
    // 设置当前状态为刷新中
    isRefresh = true;
    // 如果重发次数超过,直接退出登录
    if (currentCount > MAX_ERROR_COUNT) {
      logout();
    }
    // 增加重试次数
    currentCount += 1;

    try {
      const {
        data: { access },
      } = await UserAuthApi.refreshToken(refresh);  //用refreshToken刷新token

      localStorage.setItem('token', access)   //把新token存到本地
      // 重置重发次数
      currentCount = 0;
      // 遍历队列,重新发起请求
      queue.forEach((cb) => cb(access));//用新token吧阻塞的接口全部重新请求
      // 返回请求数据
      return request(error.config);
    } catch {
     // 刷新token失败,直接退出登录
      ElMessage.error('请重新登录')
      localStorage.clear()

      router.replace('/login')
      return Promise.reject(error);
    } finally {
       // 重置状态
      isRefresh = false;
    }
  } else {
    // 当前正在尝试刷新token,先返回一个promise阻塞请求并推进请求列表中
    return new Promise((resolve) => {
      // 缓存网络请求,等token刷新后直接执行
      queue.push((newToken) => {
        Reflect.set(config.headers, 'authorization', newToken);
        resolve(request(config));
      });
    });
  }
}```

你可能感兴趣的:(javascript,前端,vue.js)