使用Axios封装一个完整的请求交互模块

在前端开发中,要与后端完成数据交互,我们通常需要借助一下Ajax的http库来完成与后台数据接口的对接,jQuery盛行时代,我们会使用$.ajax()来实现交互,现如今已有许多现成的http库,例如:SuperAgent、Axios、Fetch…等等。有了这些http库我们不需要太多的去了解Ajax底层的工作原理,只需要关注一个请求的request的组成以及如何处理一个response即可,虽然一定程度上简化了交互,但这样在实际应用中还是远远不够的

今天来教教大家如何使用Axios封装一个完整的请求交互模块:

首先封装前我们应该思考:一个请求发起前应该做什么,请求得到响应后应该做什么,一般来说,请求前我们会设定一下公共的请求headers和请求根地址,请求时需要展示一个表示正在Loding的组件,响应回来后,根据后端返回的请求结果,判断一下请求是否成立,成功的话就按照业务逻辑来处理,不成立就需要展示后端返回的错误信息等等,以上这些公共的处理,我们都应当封装起来,而不应该在单独一个请求里重复编写

好吧,我们开始进入正文:

单独创建一个api.js文件:

先定义公共头部和根地址

//导入依赖模块
import axios from "axios";
import Router from "../router";
import qs from "qs";
import store from '../store'
 
// 默认的根地址,一般来说会有一个测试环境和生产环境
axios.defaults.baseURL = "https://test.com"; // 测试环境
// axios.defaults.baseURL = "https:/product.com"; // 线上环境
 
//设置公共请求头部
//axios.defaults.headers.A=""
//axios.defaults.headers.B=""


如果引入了vueX, store.js文件中定义一个isLoading状态:

export default new Vuex.Store({
  state: {
    isLoading: false, //请求加载状态
},
 mutations: {
  setLoading(state, data) {
      state.isLoading= data
    },
}
})


请求前后的处理:

// request 拦截器 
axios.interceptors.request.use(
  config => {
 // 登录后的token定义至headers
  if(localStorage.getItem("loginTk"))
  config.headers.token= localStorage.getItem("loginTk");
   // 使用vueX来实现loading组件的展示
    store.commit('setLoading',true);
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);
//以我这个项目作为例子,后端返回的结果是这种形式
 {
   code:200, // 响应状态码 200-请求成立 4001-登录过期 400-请求异常
   data:""   // 响应数据
   msg:""    // 响应信息
  }
 
//response 拦截器
axios.interceptors.response.use(
  response => {
   // 隐藏loding组件
    store.commit('setLoading',false)
 // 请求成功
   if( response.data.code ===200 )
    {  
     return response;
    }
// 登录失效
   else if (
      response.data.code === 40001 
    ) {
      localStorage.removeItem("loginTk");
      Router.push({ name: "login" });
      return false;
    }
// 请求异常
  else{
   message.error(response.msg);
   }
    
  },
  error => {
    return Promise.reject(error);
  }
);


loding组件定义在根路由App.vue里:

<template>
  <div id="app" >
    <router-view />
    <div  v-if="$store.state.isLoading">
       需要展示的loading组件
    </div>
  </div>
</template>


再根据请求方式和数据类型进行封装:

/* 
* 封装get方法
 * @param url
 * @param params
 * @returns {Promise}
 */
export function fetch(url, params = {}) {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params,
        headers: { "Content-Type": "application/x-www-form-urlencoded" }
      })
      .then(response => {
        resolve(response.data);
      })
      .catch(err => {
        reject(err);
      });
  });
}
/*
 * 封装post请求
 * @param url
 * @param data
 * @returns {Promise}
 */
// json格式
export function post(url, data) {
  return new Promise((resolve, reject) => {
    axios.post(url, data).then(
      response => {
        resolve(response.data);
      },
      err => {
        reject(err);
      }
    );
  });
}
// formData格式
export function From(url, data) {
  return new Promise((resolve, reject) => {
    axios
      .post(url, qs.stringify(data), {
        headers: { "Content-Type": "application/x-www-form-urlencoded" }
      })
      .then(
        response => {
          resolve(response.data);
        },
        err => {
          reject(err);
        }
      );
  });
}


到这里差不多就封装完成了,但我们应该如何简单使用呢?

进入main.js文件修改:

import Vue from "vue";
// 导入封装后的请求模块
import { post, fetch, From, } from "./api";
 
//将封装后的请求方法注入至Vue实例原型
Vue.prototype.$post = post;
Vue.prototype.$fetch = fetch;
Vue.prototype.$From = From;


然后你哪里需要请求直接通过this.$方法名调用即可:

this.$(方法名) (url,{请求参数}).then(res=>{
if(res){
 // 处理逻辑
}
})
// 针对请求结果我们已经做了处理,只需要判断有无res,有的话那请求就是成立的


到这里差不多就大功告成了,经过一系列封装后我们只需要对正确的请求进行处理,其他的都不用管了,这样写起来是不是很爽?

拓展:

有人肯定会问,如果我这个项目不需要vueX,就为了展示一个loding组件就引入进来是不是有点浪费?

如果不需要vueX,你可以这样做:

改写App.vue:

<template>
  <div id="app" >
    <router-view />
    <div  v-if="isLoading">
       需要展示的loading组件
    </div>
  </div>
</template>
<script>
 
import qs from "qs";
import Vue from "vue";
import axios from "axios";
export default {
  name: "App",
  data() {
    return {
      isLoading: false,
    };
  },
 created() {
 // request 拦截器 
 axios.interceptors.request.use(
  config => {
   //改成data中的isLoding
    this.isLoading=true
    return config;
  },
  error => {
    return Promise.reject(error);
  }
)
 
//response 拦截器
axios.interceptors.response.use(
  response => {
   // 隐藏loding组件
   this.isLoading=false
 // 请求成功
   if( response.data.code ===200 )
    {  
     return response;
    }
// 登录失效
   else if (
      response.data.code === 40001 
    ) {
      localStorage.removeItem("loginTk");
      this.$router.push({ name: "login" });
      return false;
    }
// 请求异常
  else{
   message.error(response.msg);
   }
  },
  error => {
    return Promise.reject(error);
  }
);
    Vue.prototype.$post = this.post;
    Vue.prototype.$fetch = this.fetch;
    Vue.prototype.$From = this.From;
 
  },
  methods: {
 
 fetch(url, params = {}) {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params,
        headers: { "Content-Type": "application/x-www-form-urlencoded" }
      })
      .then(response => {
        resolve(response.data);
      })
      .catch(err => {
        reject(err);
      });
  });
},
 
post(url, data) {
  return new Promise((resolve, reject) => {
    axios.post(url, data).then(
      response => {
        resolve(response.data);
      },
      err => {
        reject(err);
      }
    );
  });
},
 
From(url, data) {
  return new Promise((resolve, reject) => {
    axios
      .post(url, qs.stringify(data), {
        headers: { "Content-Type": "application/x-www-form-urlencoded" }
      })
      .then(
        response => {
          resolve(response.data);
        },
        err => {
          reject(err);
        }
      );
  });
}
  }
};
</script>


所有的封装函数都定义至在根路由里,在created周期里注入原型
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值