vue 封装 Axios详解

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

vue接口数据请求一般都使用的axios,先来看一下axios的部分常用配置项:

 // `url` 是用于请求的服务器 URL
  url: '/user',

  // `method` 是创建请求时使用的方法
  method: 'get', // default

  // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  baseURL: 'https://some-domain.com/api/',

  // `transformRequest` 允许在向服务器发送前,修改请求数据
  // 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
  // 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
  transformRequest: [function (data, headers) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
  transformResponse: [function (data) {
    // 对 data 进行任意转换处理
    return data;
  }],

  // `headers` 是即将被发送的自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // `params` 是即将与请求一起发送的 URL 参数
  // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  params: {
    ID: 12345
  },

   // `paramsSerializer` 是一个负责 `params` 序列化的函数
  // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
  paramsSerializer: function(params) {
    return Qs.stringify(params, {arrayFormat: 'brackets'})
  },

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },

  // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  timeout: 1000,

拦截器 

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

如果你想在稍后移除拦截器,可以这样:

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

可以为自定义 axios 实例添加拦截器

const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

上面所列只是部分请求配置项,也是最常用的,想要更多了解可以看axios官网,很详细。

 

项目中使用主要是对axios进行封装,以便后续使用,所以这里主要分享下项目封装的axios方法

第一种:

import axios from 'axios'
import { Message, MessageBox } from 'element-ui' // 弹窗组件
import store from '@/store' // 状态管理
import { getToken } from '@/utils/auth' // 获取cookie
import qs from 'qs'

// create an axios instance
// 新建一个 axios 实例
const service = axios.create({ 
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 100000 // request timeout
})

// 发送请求前对请求数据进行处理
service.defaults.transformRequest = [function(data) {
  /**
   * axios默认请求Context-type是application/json,也就是默认发送json格式参数,后台需要用@RequestBody进行处理
   * 这里统一用qs对请求参数进行格式化成FormData格式
   */
  return qs.stringify(data)
}]

// 请求拦截器
service.interceptors.request.use(config => {
  // Do something before request is sent
  // 配置 如果是首页导出 超时时间设置为5min(下面的path是请求的url,这是之前的写法)
  // if (config.url === '/homePageStatis/entireSuperviseExcel' || config.url === '/homePageStatis/alarmHandleInfoExcel' || config.url === '/homePageStatis/callAlarmAccidentExcel' || config.url === '/homePageStatis/callAlarmViolationExcel') {
  //   config.timeout = 1000 * 60 * 5
  // }
  // 导出时 超时时间设为5min
  if (config.responseType === 'blob') {
    config.timeout = 1000 * 60 * 5
  }
  if (store.getters.token) {
    // 让每个请求携带token-- ['XN-Auth']为自定义Header key
    config.headers['XN-Auth'] = getToken()
  }
  return config
}, error => {
  // Do something with request error
  Promise.reject(error)
})

// 响应拦截器
service.interceptors.response.use(
  /* response => {
    return response.data
  }, */
  /**
   * 通过在response里自定义code来标示请求状态,这里根据不同的code情况做相应的处理<br>
   * 也可以通过XMLHttpRequest对象状态码标识进行相应的处理
   */
  response => {
    const res = response.data
    // alert(JSON.stringify(response.data))
    if (res.code !== 0) {
      // 1004:Token 过期了
      if (res.code === 1004) {
        // 请自行在引入 MessageBox
        MessageBox.confirm('您已退出系统,可以继续留在该页面,或者重新登录', '确定登出', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          store.dispatch('FedLogOut').then(() => {
            location.reload() // 为了重新实例化vue-router对象 避免bug
          })
        }).catch(() => {
        })
        // 统一处理系统异常,不再发给上层业务(在这里统一处理后就不需要在单个组件中处理)
      } else if (res.code === 1001 || res.code === 1002 || res.code === 1003 || res.code === 1005 || res.code === 1006 || res.code === 1007 || res.code === 1008 || res.code === 1009 || res.code === 1010 || res.code === 2011) {
        Message({
          message: res.msg,
          type: 'info',
          duration: 1 * 1000
        })
      } else { // 对其它返回状态码是非0的情况,这里捕获并返回reject的Promise对象,上层业务通过catch处理异常信息
        return Promise.reject(res)
      }
    } else {
      return res
    }
  },
  error => { // 对XMLHttpRequest状态码非200的处理
    console.log('err:' + JSON.stringify(error)) // for debug
    Message({
      message: error.message,
      type: 'info',
      duration: 3 * 1000
    })
    return Promise.reject(error)
  })

export default service

这里还算是比较详细了,相信大家应该都能看的懂~~

封装是这样封装了,那么怎么调用呢?     直接传入配置项即可

// 项目中同一模块下的接口是可以统一管理的,新建一个文件夹
// 引入axios

import request from '@/utils/request'

// get方法(prodata为形参,名字随便起)
export function carlist(prodata) {
  return request({
    url: '/base/vehicle',
    method: 'get',
    params: prodata
  })
}

// post方法(data即  data: data)
export function addMsg(data) {
  return request({
    url: '/alarm/record/contentModle',
    method: 'post',
    data
  })
}

// put方法
export function driverStatus(params) {
  return request({
    url: `/event/${params.id}?status=${params.status}`,
    method: 'put'
  })
}

// delete方法
export function deleteMsg(id) {
  return request({
    url: `/alarm/record/contentModle/${id}`,
    method: 'delete'
  })
}

页面调用直接引入定义调用方法的文件,直接在页面使用即可。 

 

第二种:

import axios from "axios";
import { Message } from "element-ui";
import { Loading } from "element-ui";
import store from "@/store";
import qs from "qs";
const operator = (function () { // 服务方式创建一个加载中的loading,引用elementUI的组件
  let loadingInstance = null;
  return {
    QUERY_ERROR: "数据有误",
    hasLoading: true,
    loading(flag) {
      this.hasLoading = flag;
      if (this.hasLoading) {
        loadingInstance = Loading.service({
          lock: true,
          fullscreen: true,
          text: "Loading",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.5)"
        });
      }
    },
    close() {
      loadingInstance && loadingInstance.close();
    }
  };
})();

const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  // timeout: 50000, 
  proxy: {}
});

// 发送请求前对请求数据进行处理
// service.defaults.transformRequest = [
//   function(data) {
//     /**
//      * axios默认请求Context-type是application/json,也就是默认发送json格式参数,后台需要用@RequestBody进行处理
//      * 这里统一用qs对请求参数进行格式化成FormData格式
//      */
//     return qs.stringify(data); // 用qs将对象转换成拼接的字符串
//   }
// ];

// request 拦截
service.interceptors.request.use(
  config => {
    // console.log(store.getters.authorizationToken);
    config.headers = {
      "Content-Type": "application/x-www-form-urlencoded",
      // "Content-Type": "application/json",
      Authorization: `Bearer ${store.getters.authorizationToken}`
      //'token':localStorage.getItem('token')
    };
    operator.loading(config.hasLoad);
    // if (config.method == "post") {
    //   config.params = {};
    // }
    return config;
  },
  error => {
    // operator.close();
    Promise.reject(error);
  }
);

// respone 拦截
service.interceptors.response.use(
  response => {
    // let res = response.data;
    if (response.status === 200) {
      let data = response.data;
      let total = 0;
      // 由于后台框架的原因,请求响应数据中没有返回列表的数据总数,而是在响应头中以x-total-count
      // 的字段形式体现,所以在这里做一下修改
      if (response.headers["x-total-count"]) {
        total = response.headers["x-total-count"];
      }
      // if (data) {
      // Object.prototype.toString.apply(data.total);
      // if (Object.prototype.toString.apply(data.total) === "[object Number]") {
      //   data["pagination"] = {
      //     pageNum: data.pageNum, //当前页数
      //     pageSize: data.pageSize, //显示数量
      //     total: data.total,
      //     pageCount: data.pages
      //   };
      // }
      // }
      resStatus();
    // 因为请求响应数据中没有data字段,所以在这里添加
      return { data: data, total: total };
    } else {
      resStatus();
    }

    function resStatus() {
      setTimeout(() => {
        operator.close();
      }, 200);
    }
  },
  error => {
    var reg = RegExp(/404/);
    if (reg.test(error.message)) {
      $request.status = {
        errorMessage: error.message,
        errorType: error.request.status
      };
      // window.location.href = 'http://localhost:8080/#/error404'
    }
    Message({
      message: error.message,
      type: "error"
    });
    operator.close();
    return Promise.reject(error);
  }
);

// get post put delete方法封装
const $request = {
  get: function (url, params, load) {
    let hasLoad = false;
    if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
      hasLoad = load;
    }
    return service({
      url: url,
      method: "get",
      params: params,
      hasLoad: hasLoad
    });
  },
  post: function (url, params, load) {
    let hasLoad = false;
    if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
      hasLoad = load;
    }
    return service({
      url: url,
      method: "post",
      params: params,
      // data: params,
      hasLoad: hasLoad
    });
  },

  delete: function (url, params, load) {
    let hasLoad = false;
    if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
      hasLoad = load;
    }
    return service({
      url: url,
      method: "delete",
      params: params,
      hasLoad: hasLoad
    });
  },

  put: function (url, params, load) {
    let hasLoad = false;
    if (typeof Array.prototype.pop.apply(arguments) === "boolean") {
      hasLoad = load;
    }
    return service({
      url: url,
      method: "put",
      params: params,
      hasLoad: hasLoad
    });
  },
  axios: service,
  status: ""
};

export default $request;

调用:

import $http from '@/utils/request'
// 调用方法如同这种方式,切换方法只是更换方法明便可,如get、post等
// 这里创建了一个promise对象返回请求结果
queryTableData = params => {
    return new Promise((resolve, reject) => {
      let url = "/api/vehicle/areaNetworkStatistics";
      this.$https.get(url, params).then(response => {
        resolve(response);
      });
    });
  };

页面调用方法同上。 

 

第三种:

/* eslint-disable */
import axios from 'axios'; // 引入axios
import QS from 'qs'; // 引入qs模块,用来序列化post类型的数据,后面会提到
import Vue from 'vue';
import store from '@/store';
import router from '@/router';
let ipcRenderer = window.ipcRenderer;
import cookie from '@/router/cookies'
const pc = axios.create({
  timeout: 20000,
  baseURL: process.env.VUE_APP_API
});
//HttpRequest拦截器
pc.interceptors.request.use(
  async (config) => {
    // 获取token
    let result = await new Promise((resolve, reject) => {
      //获取用户TOKEN 信息
      var realToken = localStorage.getItem("pcToken");
      if (realToken) {
        config.headers.authorization = `Bearer ${realToken}`
      }

      resolve(config);
    });
    return result;


    // config.headers.authorization = `Bearer d3480236-c501-45ea-b3c2-5f540b806660`
    // return config

  },
  (err) => {
    return Promise.reject(err);
  }
);

//HttpResponse拦截器
pc.interceptors.response.use(
  (response) => {
    console.log("执行了HttpResponse")
    if (response.data.code == 1 || (response.data.code == 500 && response.data.msg && response.data.msg == '身份验证失败')) {
      //假如用户登录过期,则提示用户登录对话框
      let msg = Vue.prototype;
      //假如用户登录过期,则提示用户登录对话框
      if (store.state.isTrue) {
        store.commit('SET_ISTRUE', false)
        msg.$alert('当前用户登录信息过期了,请重新登录', '温馨提示', {
          confirmButtonText: '确定',
          callback: action => {
            localStorage.setItem('isFailure', true)

            store.dispatch("logout");

            cookie.cookieClear("token")
            localStorage.removeItem("autoLogo");
            localStorage.removeItem("pcToken");
            localStorage.removeItem("token");
            localStorage.removeItem("resData");
            ipcRenderer.send("resetWinSize");
            router.push("/");
          }
        });
      } else {
        return response;
      }
    }
    return response;
  },
  (error) => {
    return Promise.reject(error)
  }
);


/**
 * GET请求方式
 * @param {*} url
 * @param {*} params
 */
export function get(url, params = {}) {
  return new Promise((resolve, reject) => {
    pc.get(url, {
      params: params
    })
      .then(response => {
        if (response.data.code === 200 || response.data.code === 0) {
          //返回成功处理  这里传的啥 后续调用的时候 res就是啥
          resolve(response.data); //我们后台所有数据都是放在返回的data里所以这里统一处理了
        } else {
          //错误处理
          resolve(response.data);
        }
      })
      .catch(err => {
        reject(err);
        let message = '请求失败!请检查网络';
        //错误返回
        if (err.response) {
          message = err.response.data.message;
        }
        console.log(message);
      })
  })
}

/**提交JSON数据
 * @param url
 * @param data
 * @returns {Promise}
 */

export function postJSON(url, data = {}) {
  return new Promise((resolve, reject) => {
    pc.post(url, data)
      .then(response => {
        if (response.data.code === 200 || response.data.code === 0) {
          resolve(response.data);
        } else {
          resolve(response.data);
        }
      }, err => {
        reject(err);
        let message = '请求失败!请检查网络';
        if (err.response) {
          message = err.response.data.message;
        }
        console.log(message);
      })
  })
}

/**
 * 提交表单数据
 * @param {*} url
 * @param {*} data
 */
export function postForm(url, data = {}) {
  return new Promise((resolve, reject) => {
    pc({
      method: 'post',
      url: url,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }, // 请求头,发送FormData格式的数据,必须是 这种请求头。
      data: QS.stringify(data)
    }).then(response => {
      if (response.data.code === 200 || response.data.code === 0) {
        resolve(response.data);
      } else {
        resolve(response.data);
      }
    }, err => {
      reject(err);
      let message = '请求失败!请检查网络';
      if (err.response) {
        message = err.response.data.message;
      }
      console.log(message);
    })
  })
}

调用:单独文件定义方法,导出方法。

import * as PcHttpKit from '@/utils/http/PCHttpKit';
let IM = "sgb-im"
const ImApi = {
    // 督办列表
    apiDingList:(data)=> PcHttpKit.postJSON(`${IM}/ding/list`, data),
    // 督办一键标记已读
    dingReadAll:(data)=> PcHttpKit.postJSON(`${IM}/ding/readAll`, data),
    // 删除督办
    dingRemove:(data)=>PcHttpKit.get(`${IM}/ding/remove`,data)
}
export default ImApi;

 页面调用如下:

import api from "@/api/apiDing"; // 页面引入
// 调用方法,获取数据
async getDingList() {
   let {data} = await api.apiDingList({type:this.on + 1,userId:this.$store.state.user.no})
   this.superviseList = data; // 赋值
},

// 如果不使用async,可以.then
getDingList() {
    let data = api.apiDingList({type:this.on + 1,userId:this.$store.state.user.no})
    .then((res) => { // 正确执行
        this.superviseList = data; // 赋值
    }).catch((err) = >{ // 异常
        console.log(err)
    })
}

上面两种方法的页面调用方式同最后一种页面调用方式相同。

那么基本的封装调用就是这样,细节的东西可以去看官网。

那么,如果没有看懂的话可能是我写的不够详细吧,推荐一篇大神的博文--》vue中Axios的封装和API接口的管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值