• vue中Axios的封装和API接口的管理


    1.http.js中axios封装的优化,先直接贴代码:

    /**
     * axios封装
     * 请求拦截、响应拦截、错误统一处理
     */
    import axios from 'axios';
    import router from '../router';
    import store from '../store/index';
    import { Toast } from 'vant';
    
    /** 
     * 提示函数 
     * 禁止点击蒙层、显示一秒后关闭
     */
    const tip = msg => {    
        Toast({        
            message: msg,        
            duration: 1000,        
            forbidClick: true    
        });
    }
    
    /** 
     * 跳转登录页
     * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
     */
    const toLogin = () => {
        router.replace({
            path: '/login',        
            query: {
                redirect: router.currentRoute.fullPath
            }
        });
    }
    
    /** 
     * 请求失败后的错误统一处理 
     * @param {Number} status 请求失败的状态码
     */
    const errorHandle = (status, other) => {
        // 状态码判断
        switch (status) {
            // 401: 未登录状态,跳转登录页
            case 401:
                toLogin();
                break;
            // 403 token过期
            // 清除token并跳转登录页
            case 403:
                tip('登录过期,请重新登录');
                localStorage.removeItem('token');
                store.commit('loginSuccess', null);
                setTimeout(() => {
                    toLogin();
                }, 1000);
                break;
            // 404请求不存在
            case 404:
                tip('请求的资源不存在'); 
                break;
            default:
                console.log(other);   
            }}
    
    // 创建axios实例
    var instance = axios.create({    timeout: 1000 * 12});
    // 设置post请求头
    instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    /** 
     * 请求拦截器 
     * 每次请求前,如果存在token则在请求头中携带token 
     */ 
    instance.interceptors.request.use(    
        config => {        
            // 登录流程控制中,根据本地是否存在token判断用户的登录情况        
            // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token        
            // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码        
            // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。        
            const token = store.state.token;        
            token && (config.headers.Authorization = token);        
            return config;    
        },    
        error => Promise.error(error))
    
    // 响应拦截器
    instance.interceptors.response.use(    
        // 请求成功
        res => res.status === 200 ? Promise.resolve(res) : Promise.reject(res),    
        // 请求失败
        error => {
            const { response } = error;
            if (response) {
                // 请求已发出,但是不在2xx的范围 
                errorHandle(response.status, response.data.message);
                return Promise.reject(response);
            } else {
                // 处理断网的情况
                // eg:请求超时或断网时,更新state的network状态
                // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
                // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
                if (!window.navigator.onLine) {
                   store.commit('changeNetwork', false);
                } else {
                    return Promise.reject(error);
                }
            }
        });
    
    export default instance;
    

      

    这个axios和之前的大同小异,做了如下几点改变:

    1.去掉了之前get和post方法的封装,通过创建一个axios实例然后export default方法导出,这样使用起来更灵活一些。

    2.去掉了通过环境变量控制baseUrl的值。考虑到接口会有多个不同域名的情况,所以准备通过js变量来控制接口域名。这点具体在api里会介绍。

    3.增加了请求超时,即断网状态的处理。说下思路,当断网时,通过更新vuex中network的状态来控制断网提示组件的显示隐藏。断网提示一般会有重新加载数据的操作,这步会在后面对应的地方介绍。

    4.公用函数进行抽出,简化代码,尽量保证单一职责原则。

    下面说下api这块,考虑到一下需求:

    1.更加模块化

    2.更方便多人开发,有效减少解决命名冲突

    3.处理接口域名有多个情况

    这里这里呢新建了一个api文件夹,里面有一个index.js和一个base.js,以及多个根据模块划分的接口js文件。index.js是一个api的出口,base.js管理接口域名,其他js则用来管理各个模块的接口。

    先放index.js代码:

    /** 
     * api接口的统一出口
     */
    // 文章模块接口
    import article from '@/api/article';
    // 其他模块的接口……
    
    // 导出接口
    export default {    
        article,
        // ……
    }
    

      

    index.js是一个api接口的出口,这样就可以把api接口根据功能划分为多个模块,利于多人协作开发,比如一个人只负责一个模块的开发等,还能方便每个模块中接口的命名哦。

    base.js:

    /**
     * 接口域名的管理
     */
    const base = {    
        sq: 'https://xxxx111111.com/api/v1',    
        bd: 'http://xxxxx22222.com/api'
    }
    
    export default base;
    

      

    通过base.js来管理我们的接口域名,不管有多少个都可以通过这里进行接口的定义。即使修改起来,也是很方便的。

    最后就是接口模块的说明,例如上面的article.js:

    /**
     * article模块接口列表
     */
    
    import base from './base'; // 导入接口域名列表
    import axios from '@/utils/http'; // 导入http中创建的axios实例
    import qs from 'qs'; // 根据需求是否导入qs模块
    
    const article = {    
        // 新闻列表    
        articleList () {        
            return axios.get(`${base.sq}/topics`);    
        },    
        // 新闻详情,演示    
        articleDetail (id, params) {        
            return axios.get(`${base.sq}/topic/${id}`, {            
                params: params        
            });    
        },
        // post提交    
        login (params) {        
            return axios.post(`${base.sq}/accesstoken`, qs.stringify(params));    
        }
        // 其他接口…………
    }
    
    export default article;
    

      

    1.通过直接引入我们封装好的axios实例,然后定义接口、调用axios实例并返回,可以更灵活的使用axios,比如你可以对post请求时提交的数据进行一个qs序列化的处理等。

    2.请求的配置更灵活,你可以针对某个需求进行一个不同的配置。关于配置的优先级,axios文档说的很清楚,这个顺序是:在 lib/defaults.js 找到的库的默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后者将优先于前者。

    3.restful风格的接口,也可以通过这种方式灵活的设置api接口地址。

    最后,为了方便api的调用,我们需要将其挂载到vue的原型上。在main.js中:

    import Vue from 'vue'
    import App from './App'
    import router from './router' // 导入路由文件
    import store from './store' // 导入vuex文件
    import api from './api' // 导入api接口
    
    Vue.prototype.$api = api; // 将api挂载到vue的原型上
    

    然后我们可以在页面中这样调用接口,eg:

    methods: {    
        onLoad(id) {      
            this.$api.article.articleDetail(id, {        
                api: 123      
            }).then(res=> {
                // 执行某些操作      
            })    
        }  
    }
    

    再提一下断网的处理,这里只做一个简单的示例:

    <template>  
        <div id="app">    
            <div v-if="!network">      
                <h3>我没网了</h3>      
                <div @click="onRefresh">刷新</div>      
            </div>    
            <router-view/>      
        </div>
    </template>
    
    <script>
        import { mapState } from 'vuex';
        export default {  
            name: 'App',  
            computed: {    
                ...mapState(['network'])  
            },  
            methods: {    
                // 通过跳转一个空页面再返回的方式来实现刷新当前页面数据的目的
                onRefresh () {      
                    this.$router.replace('/refresh')    
                }  
            }
        }
    </script>
    

     

    这是app.vue,这里简单演示一下断网。在http.js中介绍了,我们会在断网的时候,来更新vue中network的状态,那么这里我们根据network的状态来判断是否需要加载这个断网组件。断网情况下,加载断网组件,不加载对应页面的组件。当点击刷新的时候,我们通过跳转refesh页面然后立即返回的方式来实现重新获取数据的操作。因此我们需要新建一个refresh.vue页面,并在其beforeRouteEnter钩子中再返回当前页面。

    // refresh.vue
    beforeRouteEnter (to, from, next) {
        next(vm => {            
            vm.$router.replace(from.fullPath)        
        })    
    }
    

    这是一种全局通用的断网提示,当然了,也可以根据自己的项目需求操作。具体操作就仁者见仁智者见智了。

    如果更多的需求,或者说是不一样的需求,可以根据自己的需求进行一个改进。

    作者:愣锤
    链接:https://juejin.im/post/5b55c118f265da0f6f1aa354
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    winform+cefSharp实现窗体加载浏览器
    C# 实现Mqqtnet 客户端,订阅发布信息
    winform+CefSharp 实现和js交互
    C# 读取INI文件
    H5+asp.net 微信开发 遇到过的坑
    C#读取Excel文件,准换为list
    vmware pro 15.5.5 官方下载地址
    IOS部分APP使用burpsuite抓不到包原因
    CVE-2020-0796 SMBv3本地提权
    网络摄像头rtsp协议登录认证
  • 原文地址:https://www.cnblogs.com/hjptopshow/p/12455780.html
Copyright © 2020-2023  润新知