为了简化数据交互的代码以及后续代码的修改更新维护,在 Vue 项目中我们会需要对 axios 库进行进一步的封装并集中管理 api 数据请求;

axios 本质还是 ajax,不过是为了解决 ajax 繁琐的请求方式以及更好的处理回调; axios 是由 ajax 和 promise 封装的 HTTP 库; 主要这几个部分说明项目中前后端数据交互的请求管理

  • 配置和创建 axios 实例
  • 请求及响应的处理 (transformRequest 可以修改传输的数据,validateStatus 用于决定那些状态会被 catch 捕获以便于处理)
  • api 接口的管理

首先考虑在 src 文件目录下建立文件夹及文件夹 api/http.js

我们代码的封装就在 http.js 内完成,为了防止 axios 被全局'污染',我们通过创建 axios 实例和配置项开始;

Axios 封装

区分环境 baseURL/超时/请求头格式修改

import axios from 'axios'
import qs from 'qs'

const service = axios.create{
    // 区分状态,更换不同的URL
    baseURL: process.env.NODE_ENV === 'production' ? 'productionUrl' : 'devUrl',
    // 设置超时时间
    timeOut: 10000,
}
// 设置post的请求头格式
service.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded;charset=UTF-8';

请求、响应处理 (拦截器)

  • transformRequest 允许在向服务器发送请求前,修改请求数据;transformResponse 在传递给 then/catch 前,允许修改响应数据
  • axios 提供了 validateStatus 属性,用于定义对于给定的HTTP 响应状态码是 resolvereject promise。 这里提及但是可以不作修改,默认 status >= 200 && status < 300 , 其他状态均在 onReject 中进行处理;
import router from '../router'

// 序列化数据请求
service.defaults.transformRequest = data => qs.stringify(data)

const backToLogin = () => {
  router.replace({ path: '/login' })
}

// 根据 status 生成 msg 及操作
const handleErrStatus = status => {
  switch (status) {
    case 401:
      backToLogin()
      return '未授权,请重新登录'
    case 403:
      localStorage.removeItem('token')
      store.commit('clearToken')
      backToLogin()
      return '登录过期,请重新登录'
    case 404:
      return '请求的资源不存在',
  }
  String(status).match(/^(5)/) && return '服务端出错,请联系管理员'
}
// 提示
import { Toast } from 'vant'
const showMsg = msg =>
  Toast({ message: msg, duration: 1000, forbidClick: true })

// 处理请求部分的拦截
service.interceptor.request.use(
  config => {
    // 获取并设置 token
    const token = store.state.token || localStorage.getItem('token')
    token && (config.header.Authorization = token)
    return config
  },
  err => {
    Promise.error(err)
  }
)
// 处理数据的响应
service.interceptor.response.use(
  res => res,
  error => {
    const { response } = error
    // 如果有response,则说明该请求已发起,但是错误
    if (response) {
      // 全局提示
      showMsg(handleErrStatus(response.status))
      return Promise.resolve(response)
    }
    return Promise.reject(error)
  }
)

Api 的管理

为了避免重复的编写请求体以及集中管理,我们会对 getpost 请求做一次封装; 我们在 http.js 的同级下建立 api.js ;

先反过来,先确定我们想要怎样的调用形式,之后确定封装方式

//api
export const getDeviceList = data => get('api/Device/getDeviceList', data)
export const updateDevice = data => post('api/Device/updateDevice', data)

注: 当数据接口多的时候,使用模块化管理接口,api.js 为 api 集合的导出口, 而对应的模块内容参照如上所述的编写

// api.js
import funcModule1 from './funcModule1'
import funcModule2 from './funcModule2'

export default {
  funcModule1,
  funcModule2
}

如此,我们构建出返回值 Promise 对象的函数作为公用的函数

// http.js
export const get = (url, params, config = {}) => {
  return new Promise((resolve, reject) => {
      service({
        methods: 'get',
        url,
        params
      })
        .then(res => resolve(res))
        .catch(err => reject(err))
  })
}
export const post = (url, data, config = {}) => {
  return new Promise((resolve, reject) => {
      service({
        methods: 'post',
        url,
        data
        ...config
      })
        .then(res => resolve(res))
        .catch(err => reject(err))
  })
}