request.js封装

import Vue from 'vue'
import router from '@/router'
import store from '@/store'
import axios from 'axios'
import { Message } from 'element-ui'

const popupErrorMessage = (function popupErrorMessage() {
  const cacheMessage = []
  return function(message) {
    if (!message) {
      return
    }
    if (cacheMessage.indexOf(message) !== -1) {
      return
    }
    Message.error(message)
    cacheMessage.push(message)
    const timeoutId = setTimeout(() => {
      cacheMessage.splice(cacheMessage.indexOf(message), 1)
      clearTimeout(timeoutId)
    }, 1000)
  }
})()

Vue.prototype.$http = axios

const CancelToken = axios.CancelToken
class PendingRequest {
  constructor() {
    /** @type { Map<string, import('axios').Canceler> } */
    this.pendingMap = new Map()
  }

  /**
   * 发起新的请求前,清除重复请求,并生成新的请求token
   * @param {string} url - 请求的url做为唯一key
   * @returns {import('axios').CancelToken}}
   */
  cancelToken(url) {
    const { pendingMap } = this
    const key = url.split('?')[0]
    if (pendingMap.has(key)) {
      pendingMap.get(key)('取消重复请求')
    }
    return new CancelToken(cancel => {
      pendingMap.set(key, cancel)
    })
  }

  cancelAllToken() {
    const { pendingMap } = this
    pendingMap.forEach(cancelToken => cancelToken('取消重复请求'))
    pendingMap.clear()
  }

  /**
   * 删除已完成的请求token
   * @param {string} url - 请求的url做为唯一key
   */
  delete(url) {
    const key = url.split('?')[0]
    this.pendingMap.delete(key)
  }
}

const pendingRequest = new PendingRequest()

const request = axios.create({
  baseURL: process.env.VUE_APP_URL,
})

request.interceptors.request.use(
  config => {
    if (!config.noCancelPendingRequest) {
      config.cancelToken = pendingRequest.cancelToken(config.url)
    }

    const token = localStorage.getItem('token')
    if (token) {
      config.headers.token = token // 请求头部添加token
    }

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

request.interceptors.response.use(
  response => {
    const { config, data } = response
    pendingRequest.delete(config.url)

    if (data.respCode === '0000' || data.respCode === '200') {
      return Promise.resolve(data)
    }
    const errorMessage = getCustomErrorMessage(data.respCode || data.status)
    if (errorMessage === false) {
      console.error(`接口响应错误: ${config.url}\n响应内容: ${data}`)
    }
    if (!process.env.production) {
      console.warn(
        `error_code: ${data.respCode},error_message: ${data.respMsg}`,
      )
    }

    !config.noHandleErrorMessage &&
      popupErrorMessage(errorMessage || data.respMsg || data)

    return Promise.reject(data)
  },
  error => {
    const { response, config = {} } = error
    if (response) {
      const errorMessage = getHttpErrorMessage(response.status)
      errorMessage && popupErrorMessage(errorMessage)
      return Promise.reject({
        message: errorMessage,
        respCode: response.status,
      })
    } else {
      if (config.noHandleErrorMessage) {
        // 不处理错误消息
        return Promise.reject(error)
      } else if (error.message.includes('timeout')) {
        // 请求超时或者网络有问题
        popupErrorMessage('请求超时!请检查网络是否正常')
      } else if (error.message.includes('Network Error')) {
        popupErrorMessage('网络连接错误')
      } else if (error.message === '取消重复请求') {
        // 取消重复请求 不做处理
        return Promise.reject({})
      } else {
        popupErrorMessage('请求失败,请检查网络是否已连接')
      }
    }
    return Promise.reject(error)
  },
)

function getHttpErrorMessage(code) {
  switch (code) {
    case 404:
      return '网络请求不存在'
    case 503:
      return '服务器目维护中'
    case 500:
      return '服务器内部错误'
  }
}

function getCustomErrorMessage(code) {
  if (!code) {
    return false
  }
  switch (code.toString()) {
    case '403':
      handleCustom403Error()
      return '登录已失效,请重新登录'
    case '1003':
      return '没有记录被修改'
    case '1006':
      return '没有记录被删除'
  }
}

function handleCustom403Error() {
  pendingRequest.cancelAllToken()
  store.commit('CLEAR_VIEW_TAG')
  if (localStorage.getItem('token')) {
    localStorage.clear()
    router.push('/login')
  }
}

export function cancelToken(url) {
  const { pendingMap } = pendingRequest
  const key = url.split('?')[0]
  if (pendingMap.has(key)) {
    pendingMap.get(key)('取消重复请求')
  }
}

export default function(url, params = {}, config = {}) {
  return request.post(url, params, config).catch(error => {
    !process.env.production && console.log(error)
    return Promise.reject(error)
  })
}
posted @ 2022-06-17 13:17  xiaoxiao95  阅读(235)  评论(0编辑  收藏  举报