美文网首页
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