袁来如此的工作笔记
袁来如此的工作笔记
竹杖芒鞋轻胜马,谁怕? 一蓑烟雨任平生。

一个完整实用的axios封装

浏览量:223

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
        }
    });
} 


   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:

复制代码
 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则用来管理各个模块的接口。

复制代码
 // 文章模块接口 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;n\ +
                      \ left:47;n\ +
                      \ top:40;n\ +
                      \ 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;
复制代码

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


打赏