Axios 请求二次重发

定义相关变量与函数

定义 Axios 的 baseUrl

const BASE_URL = process.env.VUE_APP_BASEURL

定义 Token 的刷新状态

let isRefreshing = false

定义 Token 失效后,发送的请求的容器 – 缓存接口

let subscribers = []

定义函数, 刷新 Token 后, 将缓存的接口重新请求一次,请求发送以后,清空容器

function onAccessTokenFetched(newToken) {
  subscribers.forEach(callback => {
    callback(newToken)
  })
  // 清空缓存接口
  subscribers = []
}

定义函数,添加请求失败的接口到容器中

function addSubscriber(callback) {
  subscribers.push(callback)
}

Axios 拦截器配置

import { getUserToken } from 'your/api/path'

axios.interceptors.response.use(
  response => {
    console.log('response :>> ', response)

    // {
    //   config: {
    //     headers: {
    //       Authorization: ''
    //     }
    //     method: '',
    //     url: ''
    //   },
    //   data: {},
    //   status: 200,
    //   statusText: 'OK'
    // }

    if (response.status === 200) {
      if (response.data.code === 0) {
        return response.data.data
      }

      return Promise.reject(new Error(response.data.msg))
    } else if (response.status === 401) {
      /**
       * 将未授权接口缓存起来。retryOriginalRequest 这个 Promise 函数很关键,它一直处于等待状态。
       * 只有当 token 刷新成功后,onAccessTokenFetched 这个函数执行了回调函数,返回了 resolve 状态
       */
      const retryOriginalRequest = new Promise(resolve => {
        addSubscriber(newToken => {
          resolve(
            axios.request({
              ...response.config,
              headers: {
                ...response.config.headers,
                Authorization: newToken,
              },
            })
          )
        })
      })

      // 无感刷新Token
      if (!isRefreshing) {
        isRefreshing = true

        getUserToken({
          grant_type: 'refresh_token',
          refresh_token: localStorage.getItem('SYS_REFRESH_TOKEN'),
          scope: 'server',
        })
          .then(refreshRes => {
            const newToken = `${refreshRes['token_type']} ${refreshRes['access_token']}`
            const newRefreshToken = refreshRes['refresh_token']
            localStorage.setItem('SYS_TOKEN', newToken)
            localStorage.setItem('SYS_REFRESH_TOKEN', newRefreshToken)

            // 当刷新成功后, 重新发送缓存请求
            onAccessTokenFetched(newToken)
          })
          .catch(() => {
            // 刷新token报错的话, 就需要跳转到登录页面
            localStorage.setItem('SYS_TOKEN', '')
            localStorage.setItem('SYS_REFRESH_TOKEN', '')

            window.location.href = '/login'
          })
          .finally(() => {
            isRefreshing = false
          })
      }

      return retryOriginalRequest
    } else {
      return Promise.reject(new Error(response.statusText))
    }
  },
  error => {
    return Promise.reject(new Error(error))
  }
)