import axios from 'axios'
import {
  VueAxios
} from './axios'
import notification from 'ant-design-vue/es/notification'
import store from '@/store'
import router from '../router'
import {
  setToken,
  getToken,
  getRefreshToken,
  setRefreshToken
} from '@/utils/auth'
import qs from 'qs'
// 是否正在刷新的标记
let isRefreshing = false

// 重试队列,每一项将是一个待执行的函数形式
let retryRequests = []
// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 100000 // 请求超时时间
})
// 设置缓存时间 和缓存请求数组
var requestUrl = []
const saveTime = 500
// request拦截器

service.interceptors.request.use(
  config => {
    const sessitionToken = getToken()
    if (store.getters.token || sessitionToken) {
      const token = store.getters.token || sessitionToken
      config.headers.common['Authorization'] = 'Bearer ' + token // 让每个请求携带自定义token
    }
    if (
      config.method === 'post' ||
      config.method === 'put' ||
      config.method === 'delete'
    ) {
      // 筛选在缓存时间内未过期请求 重新赋值缓存请求数组 新数组与当前请求url 匹配
      // 如果有相等项 则判断为重复提交的请求 直接return
      const nowTime = new Date().getTime()
      requestUrl = requestUrl.filter(item => {
        return item.setTime + saveTime > nowTime
      })
      const sessionUrl = requestUrl.filter(item => {
        return item.url === config.url
      })
      if (sessionUrl.length > 0) {
        notification.error({
          message: '错误',
          description: '操作太快了,请稍等!'
        })
      }
      const item = {
        url: config.url,
        setTime: new Date().getTime()
      }
      requestUrl.push(item)
    }
    return config
  },
  error => {
    // Do something with request error
    Promise.reject(error)
  }
)

// respone拦截器
service.interceptors.response.use(
  response => {
    // 如果不是2000000直接return 返回状态码以及错误信息 response.data.code !== 2000100 &&
    if (
      response.data &&
      response.data.code !== 2000000 &&
      response.data.code &&
      typeof response.data.code === 'number'
    ) {
      notification.error({
        message: '错误',
        description: '信息:' + response.data.message || response.message
      })
      return response.data
    }
    // 402:非法的token; 50012:其他客户端登录了;  50014:Token 过期了
    if (response.code === 401 || response.code === 4010200) {
      // 请自行在引入 MessageBox
      // import { Message, MessageBox } from 'element-ui'
      // MessageBox.confirm(
      //   '你已被登出,可以取消继续留在该页面,或者重新登录',
      //   '确定登出', {
      //     confirmButtonText: '重新登录',
      //     cancelButtonText: '取消',
      //     type: 'warning'
      //   }
      // ).then(() => {
      //   store.dispatch('FedLogOut1').then(() => {
      //     location.reload() // 为了重新实例化vue-router对象 避免bug
      //   })
      // })
    }
    return response.data
  },
  error => {
    if (error.response) {
      const response = error.response.data
      if (response.code === 4010200) {
        const config = error.response.config
        if (!isRefreshing) {
          isRefreshing = true
          return getRefreshTokenFunc()
            .then((res) => {
              // 重新设置token
              setToken(res.data.access_token)
              setRefreshToken(res.data.refresh_token)
              store.commit('SET_TOKEN', res.data.access_token)
              config.headers.Authorization = 'Bearer ' + res.data.access_token
              // 已经刷新了token,将所有队列中的请求进行重试
              // @ts-ignore
              retryRequests.forEach((cb) => cb(res.data.access_token))
              // 重试完清空这个队列
              retryRequests = []
              // 这边不需要baseURL是因为会重新请求url,url中已经包含baseURL的部分了
              config.baseURL = ''
              return service.request(config)
            })
            .catch(() => {
              resetLogin()
            })
            .finally(() => {
              isRefreshing = false
            })
        } else {
          // 正在刷新token,返回一个未执行resolve的promise
          return new Promise((resolve) => {
            // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
            // @ts-ignore
            retryRequests.push((token) => {
              config.baseURL = ''
              config.headers.Authorization = 'Bearer ' + token
              resolve(service.request(config))
            })
          })
        }
      } else {
        notification.error({
          message: '错误',
          description: '信息:' + response.message
        })
      }
    } else {
      const errMsg = error.toString()
      notification.error({
        message: '错误',
        description: errMsg
      })
    }

    return Promise.reject(error)
  }
)
// 刷新token的请求方法
function getRefreshTokenFunc() {
  var grantType = 'refresh_token'
  var clientId = 'erp'
  var clientSecret = 'cloud'
  var params = qs.stringify({
    refresh_token: getRefreshToken(),
    client_id: clientId,
    client_secret: clientSecret,
    grant_type: grantType
  })

  return axios.post(process.env.BASE_API + '/oauth/token', params)
}

function resetLogin() {
  store.dispatch('FedLogOut1').then(() => {
    router.push({
      name: 'login'
    })
    location.reload() // 为了重新实例化vue-router对象 避免bug
  })
}

const installer = {
  vm: {},
  install(Vue) {
    Vue.use(VueAxios, service)
  }
}

export default service

export {
  installer as VueAxios,
  service as axios
}

Logo

前往低代码交流专区

更多推荐