送人玫瑰,手有余香,你是什么,你的世界就是什么💡
前言
本文讲解下axios在项目中的一些封装与应用,欢迎各位感兴趣的开发者阅读本文。
安装依赖
- axios安装
# yarn | npm安装
yarn add axios | npm install axios
- axios使用
import axios from "axios";
axios.post("url",{}).then((res) => {
// 接口调用成功回调
}).catch((error) => {
// 接口调用失败毁掉
});
/*
支持所有http请求以及请求取消、并发请求等功能,更多细节以及使用方法移步官方文档
文档: [axios文档](http://www.axios-js.com/zh-cn/docs/)
*/
配置axios
接下来回到本文的重点,如何去合理的配置它以提高开发效率以及可维护性。
-
创建配置文件,我们只是对axios稍作封装,因此在src下创建config文件夹,在config目录下创建
axios.js
文件 -
封装好的axios配置代码如下,将下述代码放进
axios.js
文件中。
/**
* 对axios稍作封装
* 1. 设置请求超时时间
* 2. 添加请求拦截器,在每个请求的头部添加token
* 3. 添加响应拦截器,根据服务器返回状态进行相应的结果返回
*/
"use strict";
import axiosObj from "axios";
// 导入vuex,需要获取里面存储的token,请求时带上token,如果不需要可以不用导入
import store from "../store";
const defaultConfig = {
// baseURL在此处省略配置,考虑到项目可能由多人协作完成开发,域名也各不相同,此处通过对api的抽离,域名单独配置在base.js中
// 请求超时时间
timeout: 60 * 1000,
// 跨域请求时是否需要凭证
// withCredentials: true, // Check cross-site Access-Control
heards: {
get: {
// 设置默认请求头,当需要特殊请求头时,将其作为参数传入,即可覆盖此处的默认参数
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
},
post: {
// 设置默认请求头,当需要特殊请求头时,将其作为参数传入,即可覆盖此处的默认参数(第三个参数即config)
// 例如:
// services.post(`${base.lkBaseURL}/uploads/singleFileUpload`, file, {
// headers: { "Content-Type": "multipart/form-data" }
// });
"Content-Type": "application/json;charset=utf-8"
}
}
// 在向服务器发送请求前,对数据进行处理,axios默认会序列化数据
// transformRequest:[function(data){
//
// }],
// 在传递给 then/catch 前,修改响应数据
// transformResponse:[function(data){
//
// }]
};
/**
* 请求失败后的错误统一处理,当然还有更多状态码判断,根据自己业务需求去扩展即可
* @param status 请求失败的状态码
* @param msg 错误信息
*/
const errorHandle = (status: number, msg: string) => {
// 状态码判断
switch (status) {
// 401: 未登录状态,跳转登录页
case 401:
// 跳转登录页
break;
// 403 token过期
case 403:
// 如果不需要自动刷新token,可以在这里移除本地存储中的token,跳转登录页
break;
// 404请求不存在
case 404:
// 提示资源不存在
break;
default:
console.log(msg);
}
};
// 创建实例
const _axios = axiosObj.create(defaultConfig);
// 请求拦截器
_axios.interceptors.request.use(
function(config) {
// 从vuex里获取token
const token = store.state.token;
// 如果token存在就在请求头里添加
token && (config.headers.token = token);
return config;
},
function(error) {
// Do something with request error
error.data = {};
error.data.msg = "服务器异常";
return Promise.reject(error);
}
);
// 响应拦截器
_axios.interceptors.response.use(
function(response) {
// 清除本地存储中的token,如果需要刷新token,在这里通过旧的token跟服务器换新token,将新的token设置的vuex中
if (response.data?.code === 401) {
localStorage.removeItem("token");
// 页面刷新
parent.location.reload();
}
if (response.status === 200) {
// 处理接口中的data
if (response.data?.data) {
try {
const dataObj = JSON.parse(response.data.data);
if (typeof dataObj == "object" && dataObj) {
// 为json字符串将其转为json对象
response.data.data = dataObj;
}
} catch (e) {
// 不是json字符串就不处理
return response.data;
}
}
return response.data;
}
response.data.code = -1;
response.data.msg = "服务器错误";
return response;
},
function(error) {
if (error) {
// 请求已发出,但不在2xx范围内
errorHandle(error.status, error.data.msg);
return Promise.reject(error);
} else {
// 断网
return Promise.reject(error);
}
}
);
export default _axios;
完成上述步骤后,axios的核心配置就完成了,我们来看看上述配置都做了哪些事情。
- 设置超时时间
- 请求头的集中配置
- 响应失败后对状态码进行统一处理
- 在请求拦截中添加token
- 在响应拦截中对token过期以及返回数据进行相应处理
- 接口域名抽离
- 最后将其导出,我们抽离API时会用到
抽离API和域名接口
为什么要进行API抽离?假设我们所有的请求都在业务代码中写this.$axios.get(),后期接口变更、有新的需求要多传参数过去,我们就要去业务代码里一个个去找然后进行修改,毫无维护性可言。接下来带大家来实现API分离😃
实现思路
我们将通过下述几个步骤来提高项目接口的可维护性:
- 创建接口模块文件,将具体的接口地址、参数、请求方式等写在此处,最后将其导出方便api统一出口文件引用。
- 创建接口域名文件,团队中可能会有多个接口域名,我们将其写在此处,最后将其导出方便接口模块文件引用。
- 创建api统一出口文件,将api接口根据功能划分为多个模块(步骤1),利于多人开发,团队中指定模块负责人,将所有模块在此处引入,将引用暴露出去,然后挂载到Vue原型既可通过this.$api.模块名.方法名进行引用。
实现代码
- 在src下创建api文件夹
- 创建接口域名文件
index.js
/*
* 接口域名管理
*
* */
const base = {
lk:"https://www.kaisir.cn/user",
other:"https://kf.kaisir.cn/api"
};
export default base;
- 在
api
文件夹下创建接口模块文件,命名方式为:模块名+API
。
/*
* 网站管理接口
* */
import services from '../plugins/axios'
import base from './base'; // 导入接口域名列表
const websiteManageAPI = {
// 登录
login(params){
return services._axios.post(`${base.lk}/login`,params);
},
// 测试post接口
postJSON(params){
return services._axios.post(`${base.lk}/getter/postJSON`,params);
},
// 测试get接口
getJSON(pageNo,pageSize){
return services._axios.get(`${base.lk}/getter/getJSON`,{params:{pageNo:pageNo,pageSize:pageSize}});
}
};
export default websiteManageAPI;
- 创建api统一出口文件
/**
* api统一出口
* */
// 网站管理接口
import websiteManageAPI from './websiteManageAPI';
// 其他模块接口
// 导出接口
export default {
websiteManageAPI,
// ...
}
完成上述步骤后,api文件夹中的内容如下所示。
接下来,我们可以选择将api统一出口
文件暴露出来的东西挂载至原型。或者选择按需加载,在业务代码中用到哪个模块就将其导入。
此处我们介绍下如何将其挂载至原型,在入口文件mian.js
中加入下述代码即可。
// 挂载到原型(main.js)
Vue.prototype.$api = api;
适配Vue3
在vue3中使用时,主体封装思路没变,如果项目用上了TypeScript,在axios的配置文件中会多出类型声明,如果需要将api挂载至原型上,需要声明文件中对api
进行类型声明,main.js中的挂载写法需要改为app.config.globalProperties.$api = api;
。
2020年10月20日我用Vue3将之前的项目进行了重构,适用与Vue3的axios配置代码地址如下:
api文件夹:src/api
axios配置文件:config/axios.ts
vue类型声明文件:src/shims-vue.d.ts
对Vue3重构Vue2项目感兴趣的开发者可移步:使用Vue3重构Vue2项目
实际应用
例如这样一个场景:后端的所有接口都需要登录后,根据成功登录返回的token进行访问。后端接口使用shiro+jwt实现接口鉴权和token发放
- 页面加载时,从本地存储中获取token
// App.vue,created生命周期
const token = localStorage.getItem("token");
- 判断token是否存在,如果不存在则获取
//
if(lodash.isEmpty(token)){
// 跳转登录页:此处仅用于演示,用户名和密码为固定数据,实际需求为跳转登录页面进行授权
const userInfo = {
"username":"测试",
"password":"0x89oikklsa"
};
// 调用登录api
this.$api.websiteManageAPI.login(userInfo).then((res)=>{
// 将token进行存储并更新到vuex中
localStorage.setItem("token",res.token);
this.$store.state.token = res.token;
});
}else{
// 更新vuex中的token
this.$store.state.token = token;
}
- 执行结果
- 调用其他接口,测试请求头token是否添加成功
// 测试其他接口能否调用成功
this.$api.websiteManageAPI.getJSON(1,3).then((res)=>{
console.log("接口调用成功");
console.log(res)
});
}
- 执行结果
写在最后
- 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
- 本文首发于 神奇的程序员 网站,如需转载请注明出处💌
评论区