axios封装-token过期请求中断

发布时间 2023-09-15 15:55:40作者: Cxymds
import axios from 'axios'
import { useUserStore } from '@/pinia'
import { ElMessage, ElMessageBox } from 'element-plus'
import qs from 'qs'

const service = axios.create({
  baseURL: '/api',
  withCredentials: false, // 是否携带cookie
  timeout: 30000 // 超时响应
})

// 字节流下载flag
let isBlob = false

const cancelToken = axios.CancelToken
let source = cancelToken.source()
// request 请求头配置
service.interceptors.request.use(
  config => {
    // userStore
    const userStore = useUserStore()

    // 根据请求头判断是否为字节流
    isBlob = config.responseType === 'blob'

    if (userStore.token) {
      // token放在请求头accessToken字段中
      config.headers.token = userStore.token
    }
    // 请求为表单时
    if (config.contentType === 'form') {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    }
    // get请求包含数组时,参数进行qs序列化
    if (config.method === 'get') {
      config.paramsSerializer = params => {
        return qs.stringify(params, { arrayFormat: 'repeat' })
      }
    }
    // 请求参数为空时
    config.data = config.data || {}
    config.params = config.params || {}
    config.cancelToken = source.token // 全局添加cancelToken

    return config
  },
  error => {
    console.error(error)
    return Promise.reject(error)
  }
)

// response 响应
service.interceptors.response.use(
  response => {
    // userStore
    const userStore = useUserStore()

    const res = response.data

    // 如果为字节流,直接抛出字节流,不走status验证
    if (isBlob) {
      return response
    }

    // 后台返回非200处理
    if (res.status !== 200 && res.status !== 207) {
      ElMessage({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

      // 401: token失效(2小时), 412:登录过期
      if (res.status === 401 || res.status === 412) {
        source && source.cancel('登录信息已过期') // 取消其他正在进行的请求
        const CancelToken = axios.CancelToken
        source = CancelToken.source()
        ElMessageBox.confirm('登录失效,请重新登录', '提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          userStore.logout()
        })
      }

      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    if (axios.isCancel(error)) {
      // 取消请求的情况下,中断Promise调用链
      return new Promise(() => {})
    } else {
      ElMessage({
        message: error.message,
        type: 'error',
        duration: 5 * 1000
      })
      return Promise.reject(error)
    }
  }
)

export default service