美文网首页
axios基于常见业务场景的二次封装

axios基于常见业务场景的二次封装

作者: 为光pig | 来源:发表于2020-12-03 15:29 被阅读0次

axios

axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
在前端框架中的应用也是特别广泛,不管是vue还是react,都有很多项目用axios作为网络请求库。
我在最近的几个项目中都有使用axios,并基于axios根据常见的业务场景封装了一个通用的request服务。

业务场景:

1.全局请求配置。
2.get,post,put,delete等请求的promise封装。
3.全局请求状态管理。
4.取消重复请求。
5.路由跳转取消当前页面请求。
6.请求携带token,权限错误统一管理。

默认配置

定义全局的默认配置

axios.defaults.timeout = 10000 //超时取消请求
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.baseURL = process.env.BASE_URL //挂载在process下的环境常量,在我另一篇文章有详细说明

新创建一个 axios

//-- 新创建一个 axios
let newAxios = axios.create({
    //设置请求时是否携带参数
    withCredentials:true,
    //是即将被发送的自定义请求头
    headers: {"Content-Type": "application/json"},
    //允许在向服务器发送前,修改请求数据 , 只能用在 'PUT','POST'和 'PATCH',
    //后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
    transformRequest: [function (data) {
        return data;
        // return qs.stringify(data); // 对 data 进行任意转换处理
    }],
    paramsSerializer: function(params) { //是一个负责 `params` 序列化的函数
        return qs.stringify(params, {arrayFormat: 'brackets'})
    },
}),

http request 拦截器-------------------------------------------------

newAxios.interceptors.request.use(
    config => {
        // 请求次数 ++.
        postNum++ ;
        // 如果包含日期
        if(config.data && config.data.date && config.data.date.length <= 10){
            config.data.date = config.data.date.replace(/-/g,'');
        }
        if (config.url=='research/gsty-fund-audit/unApproveNum') {
            //轮询未审批接口不要弹窗
            store.commit('upLoading',false);
        }else {
            store.commit('upLoading',true);
          // 如果 loading 没有启动
          if(!store.state.loading && !timer){
            // 超过三秒 再启动 loading
            timer = setInterval(function(){
              if(timerNum > 0){
                // 显示 loading
                store.commit('upLoading',true);
                //清空定时器
                clearInterval(timer);
                timer = null;
                timerNum = 0;
              }else{
                timerNum ++;
              }
            },300);
          }
        }
        return config;
    },
    error => {
        postNum = 0;
        timerNum = 0;
        //清空定时器
        clearInterval(timer);
        // 隐藏 loading
        store.commit('upLoading',false);
        store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
        return Promise.reject(error)
    }
);

http response 拦截器-------------------------

newAxios.interceptors.response.use(
   response => {
       //得到相应后 请求次数 --
       postNum-- ;
       //如果有错误信息,则提示
       if(response.data.code != 1){
           if(response.data.code == -1){
               store.commit('upCommentTip',{msg:'您还未登录或您的登录已超时<br>请登录后再访问',routerPath:'/login'});
           }else{
               let str = response.data.message == 'failed' ?
               response.data.data : response.data.message != '' ? response.data.message : response.data.data;
               store.commit('showErrorInfo',{type:'fail',msg:str});
           }
       }
       // 如果请求都相应了,则清除定时器
       if(postNum == 0){
           clearInterval(timer);
           timer = null;
           // 隐藏 loading
           store.commit('upLoading',false);
       }

       return response;
   },
   error => {
       postNum = 0;
       timerNum = 0;
       //清空定时器
       clearInterval(timer);
       // 隐藏 loading
       store.commit('upLoading',false);
       store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
       return Promise.reject(error)
   }
);

get、post、upload、多个方法封装

let httpObj = {
    /**
     * 封装get方法
     * @param url
     * @returns {Promise}
     */
    axios_get: function (url){
        return new Promise((resolve,reject) => {
            newAxios.get(url)
            .then(
                response => {
                    resolve(response.data);
                },
                err => {
                    reject(err)
                }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装post请求
     * @param url
     * @param data
     * @returns {Promise}
     */
    axios_post:function (url,params){
        //默认同意加 token
        if(store.state.userInfo.token != undefined && url != '/login'){
            axios.defaults.headers =  {
                "Content-Type": "application/json",
                "loginToken":store.state.userInfo.token
            }
        }
        params = JSON.stringify(params);
        return new Promise((resolve,reject) => {
            newAxios.post(url,params)
            .then(
                response => {
                    resolve(response.data);
                },
                err => {
                    reject(err)
                }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装axios_uploader请求
     * @param url
     * @param data
     * @returns {Promise}
     */
    axios_uploader:function (url,params,config){
        // 创建一个新的 请求
        let axiosUploader = axios.create({
            //设置请求时是否携带参数
            withCredentials:true,
          headers: {"Content-Type": "application/x-www-form-urlencoded"},
            transformRequest: [function (data) {
                return data;
            }],
        });
        //上传,则启用新的请求头
        return new Promise((resolve,reject) => {
            axiosUploader.post(url,params,config)
            .then(
                response => {resolve(response.data); },
                err => {  reject(err)   }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装同时执行多个请求
     * @param httpList  是一个对象数组,包含多个请求信息
     * @returns {Promise}
     */
    axios_all:function(httpList){
        let arrHttp = []; //请求数组
        for (var obj of httpList) {
            if(obj.type == 'get'){
                arrHttp.push(axios.get(obj.url));
            }else if(obj.type == 'post'){
                arrHttp.push(axios_new.post(obj.url,obj.params));
            }
        }
        return new Promise((resolve,reject)=>{
            axios.all(arrHttp)
           .then(axios.spread(function () {
                var tmp = [];
                for(var val of arguments){
                    tmp.push(val.data)
                }
                resolve(tmp);
           }));
        })
    }

整体代码

import axios from 'axios';
import qs from 'qs';
import store from '@/store'
//-- axios 全局配置
axios.defaults.baseURL = process.env.NODE_ENV === 'development' ? '/api/' : process.env.VUE_APP_HTTP_URL;
//-- 新创建一个 axios
let newAxios = axios.create({
    //设置请求时是否携带参数
    withCredentials:true,
    //是即将被发送的自定义请求头
    headers: {"Content-Type": "application/json"},
    //允许在向服务器发送前,修改请求数据 , 只能用在 'PUT','POST'和 'PATCH',
    //后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
    transformRequest: [function (data) {
        return data;
        // return qs.stringify(data); // 对 data 进行任意转换处理
    }],
    paramsSerializer: function(params) { //是一个负责 `params` 序列化的函数
        return qs.stringify(params, {arrayFormat: 'brackets'})
    },
}), timer = null, timerNum = 0 , postNum = 0;

//-- http request 拦截器-------------------------------------------------
newAxios.interceptors.request.use(
    config => {
        // 请求次数 ++.
        postNum++ ;
        // 如果包含日期
        if(config.data && config.data.date && config.data.date.length <= 10){
            config.data.date = config.data.date.replace(/-/g,'');
        }
        if (config.url=='research/gsty-fund-audit/unApproveNum') {
            //轮询未审批接口不要弹窗
            store.commit('upLoading',false);
        }else {
            store.commit('upLoading',true);
          // 如果 loading 没有启动
          if(!store.state.loading && !timer){
            // 超过三秒 再启动 loading
            timer = setInterval(function(){
              if(timerNum > 0){
                // 显示 loading
                store.commit('upLoading',true);
                //清空定时器
                clearInterval(timer);
                timer = null;
                timerNum = 0;
              }else{
                timerNum ++;
              }
            },300);
          }
        }
        return config;
    },
    error => {
        postNum = 0;
        timerNum = 0;
        //清空定时器
        clearInterval(timer);
        // 隐藏 loading
        store.commit('upLoading',false);
        store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
        return Promise.reject(error)
    }
);

//-- http response 拦截器-------------------------
newAxios.interceptors.response.use(
    response => {
        //得到相应后 请求次数 --
        postNum-- ;
        //如果有错误信息,则提示
        if(response.data.code != 1){
            if(response.data.code == -1){
                store.commit('upCommentTip',{msg:'您还未登录或您的登录已超时<br>请登录后再访问',routerPath:'/login'});
            }else{
                let str = response.data.message == 'failed' ?
                response.data.data : response.data.message != '' ? response.data.message : response.data.data;
                store.commit('showErrorInfo',{type:'fail',msg:str});
            }
        }
        // 如果请求都相应了,则清除定时器
        if(postNum == 0){
            clearInterval(timer);
            timer = null;
            // 隐藏 loading
            store.commit('upLoading',false);
        }

        return response;
    },
    error => {
        postNum = 0;
        timerNum = 0;
        //清空定时器
        clearInterval(timer);
        // 隐藏 loading
        store.commit('upLoading',false);
        store.commit('upCommentTip',{msg:error+'<br>请联系管理员',routerPath:'/login'});
        return Promise.reject(error)
    }
);

let httpObj = {
    /**
     * 封装get方法
     * @param url
     * @returns {Promise}
     */
    axios_get: function (url){
        return new Promise((resolve,reject) => {
            newAxios.get(url)
            .then(
                response => {
                    resolve(response.data);
                },
                err => {
                    reject(err)
                }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装post请求
     * @param url
     * @param data
     * @returns {Promise}
     */
    axios_post:function (url,params){
        //默认同意加 token
        if(store.state.userInfo.token != undefined && url != '/login'){
            axios.defaults.headers =  {
                "Content-Type": "application/json",
                "loginToken":store.state.userInfo.token
            }
        }
        params = JSON.stringify(params);
        return new Promise((resolve,reject) => {
            newAxios.post(url,params)
            .then(
                response => {
                    resolve(response.data);
                },
                err => {
                    reject(err)
                }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装axios_uploader请求
     * @param url
     * @param data
     * @returns {Promise}
     */
    axios_uploader:function (url,params,config){
        // 创建一个新的 请求
        let axiosUploader = axios.create({
            //设置请求时是否携带参数
            withCredentials:true,
          headers: {"Content-Type": "application/x-www-form-urlencoded"},
            transformRequest: [function (data) {
                return data;
            }],
        });
        //上传,则启用新的请求头
        return new Promise((resolve,reject) => {
            axiosUploader.post(url,params,config)
            .then(
                response => {resolve(response.data); },
                err => {  reject(err)   }
            )
            .catch(err => {
                reject(err)
            })
        })
    },
    /**
     * 封装同时执行多个请求
     * @param httpList  是一个对象数组,包含多个请求信息
     * @returns {Promise}
     */
    axios_all:function(httpList){
        let arrHttp = []; //请求数组
        for (var obj of httpList) {
            if(obj.type == 'get'){
                arrHttp.push(axios.get(obj.url));
            }else if(obj.type == 'post'){
                arrHttp.push(axios_new.post(obj.url,obj.params));
            }
        }
        return new Promise((resolve,reject)=>{
            axios.all(arrHttp)
           .then(axios.spread(function () {
                var tmp = [];
                for(var val of arguments){
                    tmp.push(val.data)
                }
                resolve(tmp);
           }));
        })
    }
}
export default httpObj;

--在main.js 将 axios 改写为 Vue 的原型属性,其他圆形组件也可以使用了

Vue.prototype.$axios_get = http.axios_get;
Vue.prototype.$post = http.axios_post;
Vue.prototype.$uploader = http.axios_uploader;

-在main.js 将

//接口请求地址urls全局引入
import urls from './tools/urls'

新建一个urls文件存放接口

export default {
    //用户模块
    user: {
        loginUser: 'sys/user/loginUser',// 获取用户的登陆信息
        findUserPermissions: 'sys/user/findUserPermissions',//获取用户的权限菜单
    },

在需要的地方调用接口

getLoginMsg(that) {
                that.$post('/sys/user/loginUser').then((res) => {
                    // console.log(res);
                    if (res.code == 1) {
                        // 更新用户信息
                        that.$store.commit('upUserInfo', res.data);
                        that.$tools.setCookie('userInfo_cookie',JSON.stringify(res.data));
                        //获取用户的菜单权限
                        that.getUserMenu(that, res.data.userId, res.data.username);
                    }
                })
            },

相关文章

网友评论

      本文标题:axios基于常见业务场景的二次封装

      本文链接:https://www.haomeiwen.com/subject/flpmwktx.html