Vue 项目中使用并封装 axios

416 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

前言

axios是一个基于promiseHTTP库,可以用在浏览器node.js中,在服务端它使用原生 node.jshttp 模块, 而在客户端 (浏览器) 则使用 XMLHttpRequests主要功能有:

  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防御CSRF/XSRF

创建项目

先使用vue-cli创建一个新的项目,配置按照自己的需要选择,默认的也可

vue create vue_axios
cd vue_axios
npm run serve

基本使用

安装和引入

npm i axios -S

Vue项目中安装其他插件的时候,可以直接在 main.js 中引入并使用 Vue.use()来注册,比如EchartsVuex等,但axios并不是vue插件,它跟jQuery一样,只是一个工具库,所以只能在每个需要发送请求的组件中即时引入。

为了解决上面的问题,我们可以在引入axios后,通过修改原型链,来在全局更方便的调用

// main.js
import axios from 'axios'
Vue.prototype.$http = axios

main.js 中添加了这两行代码之后,就能直接在组件中使用 this.$http来调用axios了。

axios为提供了几种使用的语法:axios(config)axios(url[, config])和诸如axios.get(url[, config])的请求方法别名形式,可以根据自己的习惯选择,比如下面的两种写法是一样的效果:

// axios(config)
this.$http({
  method: 'get',
  url: '/user',
  data: {
    name: 'xiaoming',
    info: '12'
  }
})
// axios.get(url[, config])
this.$http.get({
  url: '/user',
  data: {
    name: 'xiaoming',
    info: '12'
  }
})

GET请求

// 向具有指定ID的用户发出请求
this.$http.get('/user?ID=12345')
  .then(function (res) {
    console.log(res);
  })
  .catch(function (err) {
    console.log(err);
  });
// 也可以通过 params 对象传递参数
this.$http.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (res) {
    console.log(res);
  })
  .catch(function (errr) {
    console.log(err);
  });

POST请求

this.$http.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (res) {
    console.log(res);
  })
  .catch(function (err) {
    console.log(err);
  });

并发请求

function getUserAccount() {
  return this.$http.get('/user/12345');
}
function getUserPermissions() {
  return this.$http.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
  .then(this.$http.spread(function (acct, perms) {
    //两个请求现已完成
  }));

二次封装

目的

  • 将项目的配置逻辑添加到axios的请求中,来改变接口请求的地址
  • 监听所有接口,在请求前和请求后进行拦截,如在请求前添加header,在请求后捕获catch,对异常的http状态进行处理
  • 对外只暴露一个request接口,统一各种请求的代码

思路

在项目的src目录下,本质上网络请求也是一个工具函数,所以新建一个utils文件夹,然后在里面新建用于封装axiosaxios.js文件和用于统一管理请求方法的data.js文件

axios 封装

项目环境可能有开发环境或生产环境。我们通过node的环境变量来匹配我们的默认接口。

这里为了代码的功能分离,在src下新建了config文件夹来存放切换baseUrl的文件。至此二次封装相关的项目目录如下:

image.png

index.js中,主要对生产环境和开发环境的basedUrl进行了处理,可根据自己的需要进行发散:

// index.js
export default {
  // 配置Ajax请求相关的 baseUrl
  baseUrl: {
    // 开发环境下用这个
    dev: "/api",
    // 生产环境下用这个
    pro: "",
  },
};

然后在axios.js中使用:

// axios.js
import axios from "axios";
import config from "@/config/index.js";

// 根据判断当前环境配置 baseUrl
const baseUrl =
  process.env.NODE_ENV === "development"
    ? config.baseUrl.dev
    : config.baseUrl.pro;

由于我们只想对外暴露一个request接口,所以在axios.js中导出的是axios实例,而在类中定义了所有的拦截器和请求逻辑:

// axios.js
class HttpRequest {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }
  // 定义axios的配置,用于创建axios实例
  getInsideConfig() {
    const config = {
      baseUrl: this.baseUrl,
      header: {},
    };
    return config;
  }
  // 定义axios的拦截器
  interceptors(instance) {
    // 添加请求拦截器
    instance.interceptors.request.use(
      function (config) {
        // 在发送请求之前做些什么
        return config;
      },
      function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
      }
    );

    // 添加响应拦截器
    instance.interceptors.response.use(
      function (response) {
        // 对响应数据做点什么
        return response;
      },
      function (error) {
        // 对响应错误做点什么
        console.log(error);
        return Promise.reject(error);
      }
    );
  }
  // 定义axios的请求函数,最终调用的是request
  request(options) {
    // 创建axios实例
    const instance = axios.create();
    // 获取axios的配置信息
    options = { ...this.getInsideConfig(), ...options };
    // 调用axios的拦截器
    this.interceptors(instance);
    // 返回接口请求的结果
    return instance(options);
  }
}

export default new HttpRequest(baseUrl);

请求方法的管理与使用

data.js中直接导入axios.js即可得到axios实例,在传入请求的配置信息后直接将方法导出

import axios from "./axios";
export const getMenu = (param) => {
  return axios.request({
    url: "/permisson/getMenu",
    method: "post",
    data: param,
  });
};

之后就可以在组件中直接调用了

<script>
import { getHomeData } from "@/utils/data.js";

mounted(){
    getHomeData().then((res) => {
        ...
    })
}
</script>