• 一个完整实用的axios封装


    1.先引入

    import axios from 'axios'
    import qs from 'qs'
    import router from '../router';
    import store from '../store/index';

    // 创建axios实例
    var instance = axios.create({ timeout: 1000 * 12});
    // 设置post请求头
    // instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; (可以不在这里封装)

    // 拦截器

    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中控制着一个全局的断网提示组件的显示隐藏
              // 关于断网组件中的刷新重新获取数据,会在断网组件中说明
              store.commit('changeNetwork', false);
              }
       });

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

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

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

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



    // 一些方法的封装

    /*
    * * 跳转登录页 * 携带当前页面路由,以期在登录页面完成登录后返回当前页面 */ 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);
       }}

    
    
    
    
    
    

    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;

    index.js:

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

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

    base.js:

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

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

    最后,为了方便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的原型上

    在页面中这样调用接口:

    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>
    // refresh.vue
    beforeRouteEnter (to, from, next) {
        next(vm => {
            vm.$router.replace(from.fullPath)
        })
    }

    至此全部完结。文章参考博客喵容 - 和你一起描绘生活

    这下面贴一下自己封装的。比上面稍简单些,灵活度不是很高,但适合小白,初学者配置使用,算是很实用吧。

    import axios from 'axios'
    // import qs from 'qs'
    axios.interceptors.request.use(config => {
      let append = document.getElementsByName('body')
      append.innerHTML = '<img style="position:fixed;
    ' +
                          ' left:47%;
    ' +
                          ' top:40%;
    ' +
                          ' transform: translateY(-50%),translateX(-50%);"' +
                          ' src="../../static/img/loading2.gif"/>'
      return config
    }, err => {
      return Promise.resolve(err)
    })
    
    let base= ‘’   // 接口域名
    
    export const request = (url, params,method,Func,isJson) => {
      // let _this = this;
      axios({
        method: method,
        url: `${base}${url}`,
        data: method=== 'post'? params: '',
        transformRequest: [function (data) {
          if(isJson === 1) {
            // debugger       // 判断是否json格式或者是表单提交形式
            return JSON.stringify(data)
          }
          let ret = ''
          for (let it in data) {
            ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
          }
          return ret         // 便于直接取到内部data
        }],
      headers: {
          // 认证和请求方式
          'Content-Type':  isJson === 1 ? 'application/json' : 
          'application/x-www-form-urlencoded',
          'authorization':sessionStorage.getItem('principal'),
          'token':sessionStorage.getItem('token')
        },
        params: method=== 'get'? params: '',
      }).then(data=>{
        console.log(data)
        if (data.data.code === 200) {
          Func(data.data.data)
        }else if(data.data.code === 406){
          alert(data.data.message)
        }else if(data.data.code === 401){
         window.location.href=''//上线用这个地址
        //  window.location.href='/'
        }else if(data.data.code === 400 || data.data.code === 505 || data.data.code === 404|| data.data.code === 500){
          alert('网络异常')
        }else if(data.data.code === 4011){
          // window.location.href = '' //本地
          window.location.href = '' //线上
        }else if(data.data.code === 4012){
          console.log(1111)
          request('token/refresh',{
            'authorization': sessionStorage.getItem('principal'),
            'refreshToken': sessionStorage.getItem('refreshToken')
          },'get',(res)=>{
            //缓存新的token
            console.log(res)
            let token = res.token;
            let principal = res.principal;
            let refreshToken = res.refreshToken;
            sessionStorage.setItem("token", token);
            sessionStorage.setItem("principal", principal);
            sessionStorage.setItem("refreshToken", refreshToken);
             request(url, params,method,Func);
          });
        }
      })
    }
    
    // post
    export const postRequest = (url, params,Func,isJson) => {
      request(url, params,'post',Func,isJson)
    }
    
    // uploadFileRequest  图片上传
    export const uploadFileRequest = (url, params) => {
      return axios({
        method: 'post',
        url: `${base}${url}`,
        data: params,
        headers: {
          'Content-Type': 'multipart/form-data',
          'authorization':sessionStorage.getItem('principal'),
          'token':sessionStorage.getItem('token')
          // 'authorization':'admin',
          // 'token':'740a1d6be9c14292a13811cabb99950b'
        }
      })
    }
    
    // get 
    
    export const getRequest = (url, params,Func,isJson) => {
      request(url, params,'get',Func,isJson)
    }

    main.js 引入
    
    import {getRequest,postRequest} from './api/http'
    Vue.prototype.$getRequest = getRequest;
    Vue.prototype.$postRequest = postRequest;

    token失效自动刷新,请看我另篇博客:https://www.cnblogs.com/panax/p/13393459.html

    至此结束了。相比配置只有两个文件,比较清晰。

  • 相关阅读:
    nginx结合tomcat一起使用
    Markdown速成班
    git pull VS git fetch&merge
    Spring框架学习
    WMS专业名词解释
    持续集成与灰度发布
    selenium webdriver入门
    理解HTTP session原理及应用
    linux常用命令
    转载:Mongodb start
  • 原文地址:https://www.cnblogs.com/panax/p/10942889.html
Copyright © 2020-2023  润新知