1.随着项目代码量加大,功能需求复杂化,对工具的封装成立必不可少的杀手锏。
如果项目中有200个axios请求,封装后可以节省10行,那整个项目就节省了2000行代码,可维护性也增强了。
2.请求数据时要使用loading加载提示,每次请求结束后无论成功失败或异常,都要关闭loading,但axios中只有then、catch,没有finally,作为强迫症的我又不想在then、catch中写两遍关闭loading。
于是,在封装的时候想了办法解决这个问题。
整个文章以get请求作展示,post请求大相径庭就不作详细介绍了,最后给个示例代码
axios.get('/user', {
params: {
ID: 12345
}
})
.then(response => { // 正常请求
this.tableData = response.data;
})
.catch(error => { // 出现异常
console.log(error);
});
axios.get('/user', {
params: {
ID: 12345
}
})
.then(response => { // 正常请求
if(!response || !response.data){
this.warnMsg("数据获取失败!");
this.tableData = [];
}else if(result.data.status == 0){
this.tableData = result.data;
}
})
.catch(error => { // 出现异常
this.errMsg("系统异常,数据获取失败!");
console.log(error);
});
这里的this.warnMsg()和this.errMsg()是自己封装的全局方法,用于弹出Element-ui的消息提示
3.现在为了进一步优化用户友好性,后端对相应数据进行了封装,如果请求的参数错误或一些其他原因无法成功,会给些提示。
后端返回数据格式
{
“status”: 0, // 请求状态 常用:0表示成功 1表示失败
“msg”: “成功”, // 后端提示消息,如果失败了,通过此字段返回失败原因
“data”: [] // 得到的数据
}
前端代码也对应变为:
axios.get('/user', {
params: {
ID: 12345
}
})
.then(response => { // 正常请求
if(!response || !response.data){ // 未获取到数据
this.warnMsg("数据获取失败!");
this.tableData = [];
}else if(result.data.status == 0){ // 后端返回成功
this.tableData = result.data.data;
}else {
this.warnMsg(result.data.msg); // 后端返回失败
this.tableData = [];
}
})
.catch(error => { // 出现异常
this.errMsg("系统异常,数据获取失败!");
console.log(error);
});
4.请求数据总会有网络延迟,如果延迟大了,就会让用户觉得系统卡机了,加上加载动画会看让系统看起来流畅性增强了。
这里用了Element-ui 的loading加载效果(整个项目使用的是vue+Element-ui)
请求前开启loading动画,不管请求成功或失败,请求结束后都要关闭loading
这时的代码显得有点臃肿了
this.loading = true; // 开启加载动画
axios.get('/user', {
params: {
ID: 12345
}
})
.then(response => { // 正常请求
if(!response || !response.data){ // 未获取到数据
this.warnMsg("数据获取失败!");
this.tableData = [];
}else if(result.data.status == 0){ // 后端返回成功
this.tableData = result.data.data;
}else {
this.warnMsg(result.data.msg); // 后端返回失败
this.tableData = [];
}
this.loading = false; // 关闭loading动画
})
.catch(error => { // 出现异常
this.errMsg("系统异常,数据获取失败!" + error); // 将错误信息直接显示给用户看
this.loading = false; // 关闭loading动画
});
一个功能完整的get请求,已达二十多行代码,而且每次使用时都会产生很多相同的代码,这个时候就想要自己封装成
动手开始封装
1.建立一个htttp.js 在这之前要先安装和引入axios、element、qs
import axios from 'axios';
import { Message } from 'element-ui';
import router from './router' // 引入路由
import qs from 'qs' // 使用qs对post传送的据序列化
axios.defaults.baseURL = "http://127.0.0.1:31706/" // 默认连接地址
axios.defaults.timeout = 30000; // 响应时间
axios.defaults.withCredentials = true;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; //配置请求头
/**
* http状态 status
* 200 登录成功、退出登录成功
* 210 登录失败
*
* 401 未登录、登录超时
* 403 权限不足等原因禁止访问
*/
// 拦截器
axios.interceptors.response.use(
response => {
if (response.data) {
if (response.data && String(response.data).substring(0, 15) == "") {
Message("请重新登录!");
router.push({
path: '/',
query: { redirect: router.currentRoute.fullPath }
})
}
}
return response;
},
error => {
if (error.response.data) {
if (error.response.data.status == 401) {
Message(error.response.data.message);
router.push({
path: '/',
query: { redirect: router.currentRoute.fullPath }
})
} else if (error.response.data.status == 403) {
Message(error.response.data.msg);
}
}
return Promise.reject(error.response.data);
}
)
/**
* 封装get请求
*/
export function get(url, params = {}) {
return new Promise((resolve, reject) => {
axios.get(url, { params: params })
.then(response => {
if (!response || !response.data) {
Message("数据获取失败!");
resolve({ ok: false, data: null });
} else if (response.data.status == 0) {
resolve({ ok: true, data: response.data.data });
} else {
Message(response.data.msg);
resolve({ ok: false, data: null });
}
}).catch(err => {
Message("系统异常!" + err);
resolve({ ok: false, data: null });
})
})
}
// 此处省略post请求,如果需要请在评论区留言
2.在main.js中引入
import axios from 'axios'
import {get,post} from './http'
//定义全局变量
Vue.prototype.$get=get;
Vue.prototype.$post=post;
3.在项目中使用
this.loading = true; // 开启加载动画
this.$get('/user', { ID: 12345 }).then(response => {
this.tableData = response.ok? response.data : [];
this.loading = false; // 关闭加载动画
})
铛铛铛~ 一下子少了四分之三的代码
封装完后,只需要关闭一次loading即可
上面的代码是封装好的,可能会不理解为什么封装完,axios使用的方式也变了,下面详细介绍一下封装的思路
http.js
// get方法封装
export function get(url,params={}){
return new Promise((resolve,reject) => {
axios.get(url,{
params:params
})
.then(response => {
resolve(response.data);
})
.catch(err => {
reject(err)
})
})
}
项目文件.vue
// 使用
this.$get('/getList')
.then(response => {
console.log(response)
}).catch(error => {
console.log(error );
})
现在好理解了吧,封装方法跟原生axios差不多
封装过程用到了Promise,如果想了解更多可以参考https://www.jianshu.com/p/67a6cade05f2
使用axios时Promise有且仅有两个回调参数resolve和reject,一个用于正常执行后回调,一个用于异常后回调
return new Promise((resolve,reject) => {
axios.get(url,{
params:params
})
.then(response => {
resolve(response.data);
})
.catch(err => {
reject(err)
}).finally(console.log("执行finally"))
但是这里Promise只会回调一次,如果在finally进行了回调,then和catch里面的回调就不会执行
很失望,还是没有找到合适的办法
现在错误提示信息都在封装方法里面放出了,对于回调功能,只需要告诉它请求成功或失败、请求的数据,并且不管成功或失败都可以执行一段代码,以此关闭loading
那我们就直接自己定义一个对象用于回调时返回所需数据吧,这回都回调then
.then(response => {
if (!response || !response.data) {
Message("数据获取失败!");
resolve({ ok: false, data: null }); // 回调then,返回失败提示
} else if (response.data.status == 0) {
resolve({ ok: true, data: response.data.data }); // 回调then,请求得到的数据
} else {
Message(response.data.msg);
resolve({ ok: false, data: null }); // 回调then,返回失败状态
}
}).catch(err => {
Message("系统异常!" + err);
resolve({ ok: false, data: null }); // 回调then,返回失败状态
})
这样就保证了不管成功或失败,都会回调then,只需在then里面写一次关闭即可
完整代码已在第三部分给出,如果有问题请在评论区提问