Vue-如何封装axios并且统一管理api
2019-07-23 本文已影响207人
Renaissance_
在vue项目中,经常会使用到axios来与后台进行数据交互,axios丰富的api满足我们基本的需求。但是对于项目而言,我们需要将其公共部分封装起来,比如异常处理,请求拦截等。本文讲述,如何在vue中封装axios。
-
安装
// 安装
cnpm install axios
cnpm install vue-axios
-
引入
在main.js中引入
// ajax
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios);
至此,我们可以在组件中使用axios发送get或者post请求了。但是响应处理以及请求拦截等我们还是需要统一封装的,接下来就需要封装axios。
-
封装
在src目录下面新增request文件夹。然后新增api文件夹,存放我们各个模块的api,新增index.js为各个模块api的统一出口。然后新增http.js封装axios。
目录结构如下
目录结构
index.js 内容如下,index.js的功能就是统一导出各模块api,这样我们就不用在main.js中一个个去引入了。
/**
* api导出
*/
import userApi from '@/request/api/user';//用户管理模块
import signApi from '@/request/api/sign';//登录注册模块
import caseApi from '@/request/api/case';//病例模块
import managerApi from '@/request/api/manager';//管理员模块
import ringApi from '@/request/api/ring';//管理员模块
import structApi from '@/request/api/struct';//管理员模块
import scheduleApi from '@/request/api/schedule';//管理员模块
export default {
userApi,
signApi,
caseApi,
managerApi,
ringApi,
structApi,
scheduleApi
}
以登陆模块为例子,sign.js如下,注意post和get传递参数的区别
/*
登录注册模块
*/
import axios from '@/request/http';
import querystring from 'querystring';
const signApi = {
//登录
signin(params){
return axios.post('/signin/',querystring.stringify(params));
},
//注册
signup(params){
return axios.post('/signup/',querystring.stringify(params));
},
//登出
signout(params){
return axios.get('/signout/',{params: params});
},
//获取验证码
getVerifyCodeImg(params){
return axios.get('/getVrifyCode',{params: params});
}
};
export default signApi;
http.js内容如下:
//封装axios
import Vue from 'vue'
import axios from 'axios';
import router from '../router';
import store from '../store/index';
import element from 'element-ui';
let vueobj = new Vue();
const toSignin = function (msg) {
store.dispatch("clearUserInfo");
var message = msg ? msg : "session过期,即将前往登录页面";
vueobj.$message.error({showClose: true, message: message, duration: 3000, onClose: function () {
router.replace({path: '/signin', query: {redirect: router.currentRoute.fullPath}
});
}});
}
/**
* 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码
*/
const errorHandle = (status, other) => {
// 状态码判断
switch (status) {
case 400:
vueobj.$message.error({showClose: true, message: "请求参数有误!", duration: 3000});
break;
// 401: 未登录状态,跳转登录页
case 401:
//vueobj.$message.error({showClose: true, message: "session过期,即将前往登录页面!", duration: 3000});
toSignin();
break;
// 403 token过期
// 清除token并跳转登录页
case 403:
vueobj.$message.error({showClose: true, message: "没有操作权限!", duration: 3000});
break;
// 404请求不存在
case 404:
vueobj.$message.error({showClose: true, message: "请求不存在", duration: 3000});
break;
case 500:
vueobj.$message.error({showClose: true, message: "请求失败,服务器内部错误", duration: 3000});
break;
case 504:
vueobj.$message.error({showClose: true, message: "与服务器连接失败!", duration: 3000});
break;
default:
console.log(other);
}}
// 创建axios实例
var instance = axios.create({ timeout: 1000 * 12});
// 响应拦截器
instance.interceptors.response.use(
response => {
// 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
// 否则的话抛出错误
if (response.status === 200) {
if(typeof response.data != 'undefined'){
return Promise.resolve(response);
}else{
return Promise.reject(response);
}
} else {
return Promise.reject(response);
}
},
// 服务器状态码不是2开头的的情况
// 这里可以跟你们的后台开发人员协商好统一的错误状态码
// 然后根据返回的状态码进行一些操作,例如登录过期提示,错误提示等等
// 下面列举几个常见的操作,其他需求可自行扩展
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);
//toSignin();
//vueobj.$message.error({showClose: true, message: "与服务器连接失败!", duration: 3000});
var originalRequest = error.config;
if(error.code == 'ECONNABORTED' && error.message.indexOf('timeout')!=-1 && !originalRequest._retry){
// originalRequest._retry = true
// return axios.request(originalRequest);
vueobj.$message.error({showClose: true, message: "请求超时,请稍后重试!", duration: 3000});
return Promise.reject(response);
}else{
}
}
}
);
export default instance;
在main.js中引入
import api from './request/api/index'
// 将各模块api挂载在vue实例上
Vue.prototype.$api = api
至此我们已经将axios成功封装,并且将各个模块的api统一管理,如果后台人员修改了api路径,我们不用去组件中一一修改,只需要在api文件下的模块api作修改。接下来就是使用封装好的api了
-
使用
以登陆为例,可通过$api的方式访问我们封装的api了
// 登陆
signin: function (formName) {
let that = this;
that.$refs[formName].validate((valid) => {
if (valid) {
that.loading = true;
that.$api.signApi.signin(that.signinForm).then(function (response) {
if(response.data.code == '201'){
var userinfo = response.data.result;
userinfo.isSignin = true;
that.$store.dispatch("setUserInfo", userinfo);
setTimeout(function () {
var redirect = that.$route.query.redirect;
if(redirect){
that.$router.push({path: redirect});
}else{
if( that.$store.getters.isAdmin) {
that.$router.push({path: '/manage/user'});
}else{
that.$router.push({path: '/manage/case'});
}
}
that.loading = false;
},1000);
}else{
that.loading = false;
that.$message.error({showClose: true, message: response.data.message, duration: 2000});
}
}).catch(function (response) {
that.loading = false;
that.$message.error({showClose: true, message: response.data.message, duration: 2000});
})
}else{
that.$message.error({showClose: true, message: that.$t('promotInfo.inputUnvalid'), duration: 2000});
}
})
}
-
总结
本文讲述了如何封装axios并且统一管理各个模块的api,集中管理和统一封装的方式减少了代码的冗余,提高了系统的健壮性,对实际开发中协作开发也有很大帮助。