axios的封装

在vue项目中我们一般会使用axios来实现前后端的交互,下面是常用的axios封装,包括了请求头、状态码、请求超时时间、请求方式、请求拦截器和响应拦截器等的封装:

首先需要先安装axios,使用如下命令:


npm install axios

我们一般会在src目录下新建一个文件夹api,然后在此文件夹下创建一个request.js文件,对axios的封装代码就写在request.js文件中,目录结果见下图

主要内容拆解:

1.请求超时时间设置,可根据实际项目需求而定

const request = axios.create({
  baseURL: '',
  timeout: 60000, //改成60s
})

 2.添加请求拦截器--(由于项目中有使用到上传和导入功能,参数与一般请求有区别,这里做了分类处理,如果不需要对参数做处理的,可以去掉type==='upload'的判断部分代码)

request.interceptors.request.use(
  (config) => {
    config.data = config.data || ''
    const { data, type, basic } = config.data
    if ( process.env.NODE_ENV === 'development' ) {
      config.url = `${config.baseUrl || '/api'}${config.url}`
    } else {
      config.url = `${config.url}`
    }
    if (data && basic) return config //如果传参时有传 basic 则不需要再加一次basic
    if (config.url !== '/login') {   // 判断请求是否是登录接口
      config.headers.token = localStorage.getItem('token') // 如果不是登录接口,就给请求头里面设置token
    }
    config.data = type === 'upload' ? data : formatParams(config.data)
    return config // 返回这个配置对象,如果没有返回,这个请求就不会发送出去
  },
  (error) => {
    return Promise.reject(error)
  }
)

其中basic中包括token、ver(版本号)、time(时间戳)等公共的接口参数,一般我们会在src下的utils文件夹中创建一个basic.js的文件,代码如下:

import MD5 from 'js-md5'
import SHA512 from './secret/sha512' // sha512加密
import { getToken } from '@/utils/auth.js'

/**
 * 生成32位随机正整数 0~2147483647 (2^32)
 */
export const getNonce = () => Math.floor(Math.random() * 2147483646 + 1)

/**
 * 生成basic数据
 * @param ver     {string} 必填    -- 版本号
 * @param time    {number} 必填    -- 时间戳
 * @param id      {string} 必填    -- 0
 * @param nonce   {string} 必填    -- 32位随机数
 * @param token   {string} 非必填  -- 登陆成功后必填,从后台获取,在localStorage中存取
 * @param sign    {string} 非必填  -- 签名,从后台获取,在localStorage中存取
 */
export const getBasic = ({
  ver = '1.0',
  time = new Date().getTime(),
  id = 1,
  nonce = getNonce(),
  token = getToken(),
  sign
} = {}) => {
  return { ver, time, id, nonce, token, sign }
}

/**
 * 生成sign签名
 * @param {Object} obj: 必须有pwd属性
 * @param {array} argsArray 拼接项数组
 */
export const creatSignForDpikey = (obj, argsArray) => {
  let str = ''
  let arr = argsArray
  if (!arr) {
    arr = Object.keys(obj).filter(v => v !== 'pwd')
  }
  arr.sort()
  for (let key of arr) {
    str += obj[key]
    str += '#'
  }
  str += MD5(obj['pwd'])
  let Mstr = SHA512.encrypt(str)
  return Mstr
}

2.添加响应拦截器--响应拦截器中包含对错误码的处理,此处我们一般会新建errorCode.js文件,将需要统一在页面上弹出提示的错误码写在此文件中(好处就是不需要在代码里面每个接口返回的错误码都写一次提示处理,只需要针对需要特别处理的个别错误码做处理例如提示后还有下一步操作的情况就需要特殊处理)

request.interceptors.response.use(
  (res) => {
   let langType = getLocale() || 'en-US'
    if (res.status != 200) {
      return false
    }
    let code
    if (res.data.basic) {
      code = res.data.basic.code  // 获取后端返回的状态码
      if (code === 200) { //接口状态码
        return res.data
      } else if (code === 20004 || code === 10002 || code === 7009 || code === 7088 || code === 7090 || code === 7004 ) { // Invalid token   Token expires //  Token达到最大数量后被强制退出
        if (showLoginMsg) { // token过期导致请求失败,返回登录页后只弹出一个异常提示
          Message.error(errorCode[langType][code])
          logout()
          showLoginMsg = false
          setTimeout(() => {
            showLoginMsg = true
          }, 3000)
        }
        return Promise.reject(code)
      }
      else { //例如公共的 其他code 默认3秒 改为2秒  
        Message.error(errorCode[langType][code])  //改为这种写法后 即使没有翻译 codeMsg也不为false
        if (codeMsg && (codeMsg !== `errorCode[langType][code]`)) {
          if (showOtherMsg) {
            Message({ message: codeMsg,duration: 2000,type: 'error' })
            showOtherMsg = false
            setTimeout(() => {
              showOtherMsg = true
            }, 2000)
          }
        } else if (!specialCode.includes(code)) {
          if (showOtherMsg) {
            Message({ message: res.data.basic.msg,duration: 2000,type: 'error' })
            showOtherMsg = false
            setTimeout(() => {
              showOtherMsg = true
            }, 2000)
          }

        }
        return Promise.reject(res.data)
      }
    } else {
      return res.data
    }
  },
  (error) => {
    // axios判断请求超时进行处理
    let langType = getLocale() || 'en-US'
    if (error.message.includes('timeout')) {
      if (showOtherMsg) {
        Message({
          message:message: errorCode[langType]['12345'], 
          type: 'error',
          duration: 2 * 1000,
        })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    } else if (error && error.response) {
      // 处理失败的状态码  状态码404 500 503之类的
      let statusCode = error.response.status
      if (showOtherMsg) {
        Message({ message: errorCode[langType][statusCode],duration: 2000,type: 'error' })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    } else if (error.message == 'Network Error') {
      if (showOtherMsg) {
        Message({
          message:errorCode[langType]['12344'],
          type: 'error',
          duration: 2 * 1000,
        })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    }
    return Promise.reject(error)
  }
)

request.js中的完整的代码如下:

/* eslint-disable no-undef */
import axios from 'axios'
import Vue from 'vue'
import router from '../router' // 获取路由
import { Message } from 'element-ui' // message提示信息组件
import { getBasic } from '@/utils/basic'
import { errorCode } from '@/utils/errorCode'
import { specialCode } from '@/utils/specialCode'
import { getLocale } from '@/lang'
import store from '@/store'
import { logout } from '@/utils/common'



// 生产地址
// axios.defaults.baseURL = serverBase; // 配置axios请求的地址


const request = axios.create({
  baseURL: '',
  timeout: 60000, //改成60s
})

// 格式化请求参数
const formatParams = (params) => {
  const basic = getBasic()
  return {
    basic,
    data: params
  }
}


let showLoginMsg = true
let showOtherMsg = true

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    config.data = config.data || ''
    const { data, type, basic } = config.data
    if ( process.env.NODE_ENV === 'development' ) {
      config.url = `${config.baseUrl || '/api'}${config.url}`
    } else {
      config.url = `${config.url}`
    }
    if (data && basic) return config //如果传参时有传 basic 则不需要再加一次basic
    if (config.url !== '/login') {   // 判断请求是否是登录接口
      config.headers.token = localStorage.getItem('token') // 如果不是登录接口,就给请求头里面设置token
    }
    config.data = type === 'upload' ? data : formatParams(config.data)
    return config // 返回这个配置对象,如果没有返回,这个请求就不会发送出去
  },
  (error) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
request.interceptors.response.use(
  (res) => {
   let langType =  getLocale() || 'en-US'
    if (res.status != 200) {
      return false
    }
    let code
    if (res.data.basic) {
      code = res.data.basic.code  // 获取后端返回的状态码
      if (code === 200) { //接口状态码
        return res.data
      } else if (code === 20004 || code === 10002 || code === 7009 || code === 7088 || code === 7090 || code === 7004 ) { // Invalid token   Token expires //  Token达到最大数量后被强制退出
        if (showLoginMsg) { // token过期导致请求失败,返回登录页后只弹出一个异常提示
          Message.error(errorCode[langType][code] ) 
          logout()
          showLoginMsg = false
          setTimeout(() => {
            showLoginMsg = true
          }, 3000)
        }
        return Promise.reject(code)
      }
      else { //例如公共的 其他code 默认3秒 改为2秒  
        const codeMsg = errorCode[langType][code]  //改为这种写法后 即使没有翻译 codeMsg也不为false
        if (codeMsg && (codeMsg !== `errorCode[langType][code] `)) {
          if (showOtherMsg) {
            Message({ message: codeMsg,duration: 2000,type: 'error' })
            showOtherMsg = false
            setTimeout(() => {
              showOtherMsg = true
            }, 2000)
          }
        } else if (!specialCode.includes(code)) {
          if (showOtherMsg) {
            Message({ message: res.data.basic.msg,duration: 2000,type: 'error' })
            showOtherMsg = false
            setTimeout(() => {
              showOtherMsg = true
            }, 2000)
          }

        }
        return Promise.reject(res.data)
      }
    } else {
      return res.data
    }
  },
  (error) => {
    // axios判断请求超时进行处理
    let langType =  getLocale() || 'en-US'
    if (error.message.includes('timeout')) {
      if (showOtherMsg) {
        Message({
          message: errorCode[langType]['12345'], 
          type: 'error',
          duration: 2 * 1000,
        })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    } else if (error && error.response) {
      // 处理失败的状态码  状态码404 500 503之类的
      let statusCode = error.response.status
      if (showOtherMsg) {
        Message({ message:errorCode[langType][statusCode],duration: 2000,type: 'error' })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    } else if (error.message == 'Network Error') {
      if (showOtherMsg) {
        Message({
          message: errorCode[langType]['12344'],
          type: 'error',
          duration: 2 * 1000,
        })
        showOtherMsg = false
        setTimeout(() => {
          showOtherMsg = true
        }, 2000)
      }
    }
    return Promise.reject(error)
  }
)

export default request

在项目中使用示例:

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值