Vue项目中的axios封装,结合ElementUI,增加对重复请求的拦截操作

·  阅读 597

日常生活中开发Vue的项目总是免不了要封装axios,今天得空索性写个完完整整的axios封装,结合ElementUI组件库的提示功能,实用性还是不错的。

废话少说,代码贴出如下,如有不正确的地方,欢迎指正:

import axios from 'axios'

// 这里的Message是按需导入的,和VantUI的类似,根据自己的需要决定
import { Message } from 'element-ui'

// 错误代码消息提示框
const tip = message => {
  Message({
    message,
    duration: 1000,
    type: 'error'
  })
}

// 错误代码捕获
const errorHandler = (status) => {
  switch (status) {
    case 302:
      tip('接口重定向')
      break

    case 400:
      tip('请求错误')
      break

    case 401:
      tip('未授权,请重新登陆')
      break

    case 403:
      tip('没有操作权限')
      break

    case 404:
      tip('请求地址出错')
      break

    case 405:
      tip('请求方法不被允许')
      break

    case 408:
      tip('请求超时')
      break

    case 422:
      tip('无法处理的实体')
      break

    case 500:
      tip('服务器错误')
      break

    case 501:
      tip('服务未实现')
      break

    case 502:
      tip('网关错误')
      break

    case 503:
      tip('服务不可用')
      break

    case 504:
      tip('服务暂时无法访问,请稍后再试')
      break

    case 505:
      tip('HTTP版本不受支持')
      break

    default:
      tip('系统错误,请稍候重试')
      break
  }
}

// 拦截重复的请求
// 重复的请求是指请求方式、请求路径、请求参数都一致的请求
const pendingMap = new Map()

// 生成每个请求唯一的键
function getPendingKey (config) {
  let { url, method, params, data } = config
  if (typeof data === 'string') {
    data = JSON.parse(data)
  }
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}

// 存储每个请求的唯一值
function addPendingKey (config) {
  const pendingKey = getPendingKey(config)
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingMap.has(pendingKey)) {
      pendingMap.set(pendingKey, cancel)
    }
  })
}

// 取出重复请求并且删除
function removePendingKey (config) {
  const pendingKey = getPendingKey(config)
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey)
    cancelToken(pendingKey)
    pendingMap.delete(pendingKey)
  }
}

class HttpRequest {
  // 设置基准路径
  constructor (baseURL) {
    this.baseURL = baseURL
  }

  // 设置axios的实例配置
  getInstanceConfig () {
    const config = {
      timeout: 10000,
      baseURL: this.baseURL,
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      }
    }
    return config
  }

  // 设置拦截器
  interceptors (instance) {
    // 请求拦截器
    instance.interceptors.request.use(config => {
      removePendingKey(config)
      addPendingKey(config)
      // 这里的token是用户登陆之后获取的,现在暂时乱写
      const token = 'jxnwejjwsnwjswswxwxdw'
      token && (config.headers.Authorization = `Bear ${token}`)
      return config
    }, error => {
      Promise.reject(error)
    })

    // 响应拦截器
    instance.interceptors.response.use(result => {
      removePendingKey(result.config)
      return Promise.resolve(result.data)
    }, error => {
      error.config && removePendingKey(error.config)
      const { response } = error
      if (response) {
        errorHandler(response.status)
        return Promise.reject(response)
      } else {
        if (window.navigator.onLine) {
          tip('断网了')
        } else {
          return Promise.reject(error)
        }
      }
    })
  }

  // 创建请求的实例,也可以发DELETE和PUT等请求
  request (options) {
    const instance = axios.create()
    const newOptions = Object.assign(this.getInstanceConfig(), options)
    // 拦截器操作
    this.interceptors(instance)
    return instance(newOptions)
  }

  // get请求
  get (url, config) {
    const options = Object.assign({
      method: 'GET',
      url: url
    }, config)
    return this.request(options)
  }

  post (url, data) {
    return this.request({
      url,
      method: 'POST',
      data
    })
  }
}

export default HttpRequest
复制代码
分类:
前端
标签: