vue中关于axios二次封装那点事

2,100 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

前情提要

其实针对项目大小的程度不同,对axios封装的需求也全然不同。axios本身就是封装很不错的了,所以对于一般小项目而言完全没有二次封装的意义。而二次封装往往也会配合api的统一管理来进行使用。
而对于大项目而言,需求点主要在于针对接口返回错误信息的统一处理、后端接口域名在不同环境下的切换、对接口数据的二次清洗、有主动取消请求中的接口等私人订制化需求。
而对于项目接口规范不同二次封装的方式也不同。有的项目采用的resultfull风格的接口,有的项目可能永远就固定使用一种post请求等。
所以主要分两种:

  • 根据具体请求进行封装:封装程度有限,可拓展性有限。
  • 利用axios的拦截器进行封装:封装程度高,可拓展性高。属于目前最常见的一种封装方式

根据具体请求封装(基本上不是很推荐这种写法)

  • 以post请求为例
  • /utils/axios.js
import axios from 'axios';
// 环境的切换
if (process.env.NODE_ENV == 'development') {
  axios.defaults.baseURL = 'http://aaaaaaaaaa.com';
}
else if (process.env.NODE_ENV == 'debug') {
  axios.defaults.baseURL = 'https://yyyyyyyy.com';
}
else if (process.env.NODE_ENV == 'production') {
  axios.defaults.baseURL = 'http://xxxxxxx.com';
}
axios.defaults.withCredentials = true;
axios.defaults.timeout = 30000;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';

/** 
 * post方法,对应post请求 
 * @param {String} url [请求的url地址] 
 * @param {Object} params [请求时携带的参数] 
 */
 export function post(url, data) {
  return new Promise((resolve, reject) => {
    axios.post(url, data)
      .then(res => {
        console.log(res)
        resolve(res.data);
      })
      .catch(err => {
        reject(err.data)
      })
  });
}
  • 如果项目使用了api统一管理:/api/index.js
import { axios } from '@/utils/axios'
export default {
  getInfo(params) {
    return axios('/xxx/xxx/xxx', params)
  }
}
  • 如果项目没有使用api统一管理:main.js
import Vue from 'vue'
import App from './App.vue'
import { post } from '@/utils/axios'
Vue.config.productionTip = false
Vue.prototype.$post = post
new Vue({
  render: h => h(App),
}).$mount('#app')

利用axios拦截器进行封装

  • 主要利用请求拦截器响应拦截器
  • 拦截器主要接受两个回调函数,一个是正常的回调函数,一个是错误回调函数。
  • .env.development
BASE_URL  = ‘xxxx’;
  • /utils/axios.js
import axios from 'axios';
const service = axios.create({
    // 如果不存在跨域问题并且在.env.xxx文件中有配置的话baseURL的值可以直接使用:process.env.BASE_URL;
    //如果使用proxy做了代理配置,那么baseURL的值直接填写'/'就可以了。
    baseURL: '', 
    timeout: 60000,
    headers: { // 主要进行相关请求头信息配置
        'Content-Type': ‘application/json;charset=UTF-8’,
        'token': 'xxxxxxxxx'
    }
})
// 请求拦截器:所有的请求在发起请求之初都会走这个
service.interceptors.request.use(
    async (config) => {
        ```
           上面的头部信息配置有些固定,毕竟有些接口的相关配置就那么标新立异,鹤立鸡群,那么就可以在这里
           进行动态配置.比如:config.headers.token = 'xxxxxxxx'
        ```
        // 如果需要对数据进行二次处理,同样可以在这里深度定制化处理
        // 最后将动态处理好的config返回就行了。
        return config;
    },
    (error) => {
        return Promise.reject(error);
    }
)
// 响应拦截器:所有的请求在响应之后都会走这个
service.interceptors.response.use(
    (response) => {
        // 此时接口已经请求成功,response里面便是请求成功后返回的响应体
        // 一般情况下会在这里进行一次数据的剥离。这样真正发起请求的地方就可以少写一层
        ```
           response里存在data对象,status,statusText,headers对象,config对象,request对象。
           此时我们只需要data和config: const { data, config } = response;
        ```
        ```
           项目里一般会存在文件请求,此时返回的response是二进制文件流,要做个判断:
           const { responseType } = config; if(responseType == 'blob') return response; return data;
        ```   
        ``` 
            有时虽然请求是200,但是实际接口返回的可能不是正常数据,而是自定义的错误code,这时可以在这里进行相关
            前后端协商后的相关配置。比如:code是404,则跳转到404页面。code是502,则跳转到502页面。code
            是401,则跳转到401当然也不一定非要跳转页面,也可以引入Element实例然后弹出错误或者警告信息框。
         ```
        return response;
    },
    (error) => {
        return Promise.reject(error);
    }
)
// 最后将service对象抛出去就行
export default service;