针对axios的封装

9 篇文章 0 订阅
import axios from 'axios'
import { TOKEN } from '#/utils/config'

const genFetch = (opts = {}) => {
   //xxx为某变量
  return axios.create({
    baseURL: xxxxx ? xxxxx+ 'api' : '/api',
    timeout: Infinity,
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json'
    },
    ...opts
  })
}

/**
 * API
 * @param {object} Vue Vue
 * @param {object} opts 选项
 * {
 *  notice?: (msg) => void
 *  router?: VueRouterInstance
 * }
 *
 * @example
 export default {
    async beforeMount () {
      try {
        const { error, model } = await this.$api('/role2', {
          // 声明自己处理请求状态错误,需要try catch
          $skipGlobalErrorCheck: true
        })
        if (error) {
          // 这里的错误是接口给的逻辑错误
          console.error('Biz Err: ', error, model)
          return
        }
        console.log('Done. ', model)
      } catch (err) {
        // 这里的错误是请求时错误,比如404,500等
        console.log('Err: ', err.message)
      }
    }
 }
 *
 *
 * @returns
 */
const Request = (Vue, opts) => {
  if (Request.installed) {
    return
  }

  const showMessage =
    Object.prototype.toString.call(opts.notice) === '[object Function]'
      ? opts.notice
      : (msg) => {
          console.warn('无法处理错误,未设置notice选项...')
          console.error(msg)
        }

  const buildErrorMessage = (response) => {
    if (!response) {
      return '未知错误'
    }
    return response.status ?? response.data?.model ?? response.data ?? response.statusText ?? response
  }

  const buildErrorResponse = (response) => {
    return { error: true, model: buildErrorMessage(response) }
  }

  const buildNormalResponse = (data) => {
    return { error: !data.success, model: data.data || data.message }
  }

  const $api = genFetch({
    timeout: 15000
  })

  $api.interceptors.request.use((request) => {
    if (!request.headers.Authorization) {
      // 加token
      const token = window.localStorage.getItem(TOKEN)
      if (token) {
        request.headers.Authorization = `Bearer ${token}`
      }
    }
    return request
  })

  $api.interceptors.response.use(
    (response) => {
      const { config } = response
     // xxx为特殊格式转换
      if (config.url.startsWith('/xxx/')) {
        response.data = { success: response.data.ok, message: response.data.msg, data: response.data }
      }
      // $skipGlobalResponseWrap 跳过全局响应包装步骤,获取原始响应信息
      const respData = config.$skipGlobalResponseWrap ? { data: response, success: true } : response.data
      return response.status === 200 ? buildNormalResponse(respData) : buildErrorResponse(response)
    },
    (error) => {
      // 包装错误信息
      const msg = axios.isCancel(error) ? '超时取消请求' : buildErrorMessage(error.response ?? error.status ?? error.message)
      const err = new Error(msg)
      // 用户指定跳过默认错误处理
      if (error.config.$skipGlobalErrorCheck) {
        // 往上抛出包装后的错误
        return Promise.reject(err)
      }
      if (error.response) {
        switch (error.response.status) {
          // 401,403: 跳转到登录页
          case 401:
          case 403: {
            if (typeof opts.router !== 'undefined') {
              // 有router的环境
              opts.router.replace({ name: 'login' })
            } else {
              console.warn('无法跳转到登录页,未设置router选项...')
            }
            showMessage('用户会话已失效,请重新登录')
            break
          }
          case 404: {
            showMessage('调用了不存在的接口,请检查')
            break
          }
          case 500: {
            showMessage('接口异常')
            break
          }
          default: {
            showMessage(`其他错误, Error Code: ${error.response.status}`)
            break
          }
        }
      }
      // 扶正错误
      return Promise.resolve(buildErrorResponse({ statusText: msg }))
    }
  )

  Vue.prototype.$api = $api
  
  // 兼容现有的代码
  // 最好将现有的请求接口相关的代码都更新为如下处理方式:
  // const { error, model } = await this.$api('/xxx/xxx', {
  //   params
  // })
  // if (error) {
  //   this.$Modal.error({
  //     title: '提示',
  //     content: `加载xx错误!原因:${model}`
  //   })
  //   return
  // }
  // console.log(model)
  const api = genFetch()

  api.interceptors.request.use((request) => {
    if (!request.headers.Authorization) {
      // 加token
      const token = window.localStorage.getItem(TOKEN)
      if (token) {
        request.headers.Authorization = `Bearer ${token}`
      }
    }
    return request
  })

  api.interceptors.response.use(
    (response) => {
      return response.data.model ? response.data.model : response.data
    },
    (error) => {
      return Promise.reject(error)
    }
  )
  
  Vue.prototype.fetch = api

  Request.installed = true
}

export default Request

main.js中的引用

import Request from './utils/request'

实际调用

 try {
        const { error, model } = await  this.$api.get(' xxxxx',
          {
            params:{
              xxxxx: xxxxxx,
            },
          })
        if (error) {
          // 这里的错误是接口给的逻辑错误
         
          this.$Modal.error({
            title: '提示',
            content: `查询同步任务错误!原因:${model.msg? model.msg : model}`,
          })
          return
        }

     
      } catch (err) {
        // 这里的错误是请求时错误,比如404,500等
        console.log('Err: ', err.message)
      }

感觉相对比较完善,记录一下,不喜勿喷,(#^.^#)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值