VUE 爬坑之旅 -- axios 封装

网络请求是每个项目都需要具备的功能,现在的 vue 项目中基本都是使用的 axios 作为网络请求库,老规矩,先上一份 axios中文文档
axios 本身已经封装的很好了,直接使用也是没问题的,为了在实际开发中更好更方便的使用,需要对它进行一下二次封装。二次封装要达到的效果:
1. 请求开始时,弹出加载动画,如超时,弹出提示并结束动画
2. 正常拿到请求结果后结束动画,
3. 如请求失败,弹出失败信息并结束动画
4. 请求正常,但返回的结果不对,根据返回的错误码跳转到指定页面,并弹出错误信息。比如需要登录后才能请求的接口,没有登录的话跳转到登录
5. 对常用的 get,post 请求进行封装,让它们更好用
以上,就是我们进行封装的目的和预期要达到的效果,

下面开始封装,网络请求的封装都是根据服务器返回的数据格式来进行封装的,先说下我们后台返回的数据格式,

//正常情况
{
    code:0,
    data:{
        ......
    },
    time:时间戳
}

//请求有问题,返回错误信息
{
    code:0,
    text:"......"
    time:时间戳
}

上面是我们的后台返回的数据格式,但是在实际返回的数据不是这样的,它外面还有一层,那外面的一层是 axios 的 response 数据结构,结构如下:

{
  // `data` 由服务器提供的响应
  data: {
      //这里面才是我们服务器返回的真正数据
      ......
  },

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

  // `config` 是为请求提供的配置信息
  config: {}
}

返回的数据结构有了就好办了,下面就直接贴出最终的封装代码,关键地方都有注释,在封装的这个 JS 里面,使用了 mint-ui 的二个组件,一个是 Indicator 加载动画,一个是 toast ,toast 已经在 main.js 里面全局引用过了,所以这里面是没有 import toast 的,这点注意

import axios from 'axios'
import { Indicator } from 'mint-ui'//加载中动画

//vue 实例
let vue = null
//是否允许显示toast
let showToast = true

//请求开始时,开启加载中动画,出错了提示并关闭动画
axios.interceptors.request.use(config => {
  Indicator.open()
  return config
}, error => {
  if (vue && showToast) {
    vue.toast('请求超时!')
  }
  Indicator.close()
  return Promise.reject(error)
})

//请求完成时,关闭加载中动画,返回数据或错误信息
axios.interceptors.response.use(response => {
  Indicator.close()
  //一切正常,返回数据或空对象
  if (response.data.code === 0) {
    return response.data.data || {}
  } else {
    //没有数据,只有提示信息,则弹出提示信息,
    if (response.data.text != null && response.data.text.length > 0) {
      if (vue && showToast) {
        vue.toast(response.data.text)
      }
    }
  }
}, error => {
  Indicator.close()
  if (error.response) {
    if (error.response.data.code === 10 || error.response.data.code === 6) {
      //未登录
      if (vue) {
        vue.$router.replace('/login')
      }
    } 
    // 请求已发出,但服务器响应的状态码不在 2xx 范围内,有错误信息则弹出错误信息
    console.log('response-error-data', error.response.data)
    if (error.response.data.text != null && error.response.data.text.length > 0) {
      if (vue && showToast) {
        vue.toast(error.response.data.text)
      }
    }
  } else {
    //什么数据都没有,直接出错了
    console.log('Error', error.message)
    if (vue && showToast) {
      vue.toast('网络出错了,未请求到数据')
    }
  }
})

export default class api {
  static get = (url, vueContext, isShow) => {
    showToast = true
    if (vueContext != null) {
      vue = vueContext
    }

    if (isShow === false) {
      showToast = isShow
    }

    return axios({
      method: 'get',
      url: `${BASE_URL}${url}`,
      withCredentials: true,//表示跨域请求时是否需要使用凭证
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
      },
    })
  }

  static post = (url, params, vueContext, isShow) => {
    showToast = true
    if (vueContext != null) {
      vue = vueContext
    }

    if (isShow === false) {
      showToast = isShow
    }

    return axios({
      method: 'post',
      url: `${BASE_URL}${url}`,
      data: params,
      withCredentials: true,//表示跨域请求时是否需要使用凭证
      // 发送请求前处理request的数据
      transformRequest: [
        function (data) {
          let ret = ''
          for (let it in data) {
            ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
          }
          return ret
        }],
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    })
  }
};

经过上面的封装之后,使用就简单了,只需要处理请求成功的回调就行了,其他的请求错误等等情况都可以不用管,这里已经都处理好了。

还有最后一步就是把上面 export 出来的 get ,post 方法在 main.js 中挂载到 vue 的原型上,这样就能整个项目中随意使用了。

import api from './utils/apiHelp'

Vue.prototype.api = api

比如说发起登录请求:

        this.api.get('/index/trend',this).then((data) => {
          if (data && data.indices) {
            this.indices = data.indices
          }
        })

So Easy!

你可能感兴趣的:(Vue,Vue,爬坑之旅)