封装一个好用的axios,省时又省力,真香!!
原创...2022年6月30日
简单聊一聊我在项目中是如何封装 axios 以及如何统一管理 api 接口,其主要目的是简化代码,使代码结构更清晰,便于后期更新维护。
一、初识 axios
axios
- 一个易用、简洁且高效的 http 库
它具有以下几个优点
- 支持
node
端和浏览器端 - 同样的 API,node
和浏览器全支持,平台切换无压力 - 支持
Promise
- 使用Promise
管理异步,告别传统callback
方式 - 丰富的配置项 - 支持拦截器等高级配置
- 社区支持 -
axios
相关的npm
包数量一直在增长
优点还挺多,上手试试。
二、封装 axios
1. 安装依赖
可以使用 npm、yarn 等进行安装,这里我使用 yarn
。
yarn add axios
引入axios
。我一般是在src
下创建一个utils
文件夹,在其中新建一个request.js
放置封装好的axios
。
import axios from "axios";
2. 创建实例
// 创建实例
const instance = axios.create();
// 创建实例后修改默认值
axios.defaults.baseURL =
process.env.NODE_ENV == "development"
? "http://127.0.0.1:8081"
: "https://api.example.com"; // 默认请求地址,需根据环境判断请求的路径
axios.defaults.timeout = 10000; // 超时时间,单位毫秒
axios.defaults.headers.post["Content-Type"] =
"application/x-www-form-urlencoded"; // post请求头的设置
3. 请求拦截
/**
* 请求拦截器
* 每次请求前,如果存在token则在请求头中携带token
*/
axios.interceptors.request.use(
(config) => {
LoadingBar.start();
// 添加token
const token = getToken();
token && (config.headers.Authorization = "Bearer " + token);
return config;
},
(error) => Promise.error(error)
);
4. 响应拦截
/**
* 响应拦截器
* 每次请求后,判断请求状态码是否正确,及数据做处理
*/
axios.interceptors.response.use(
/**
* 传输层:接口正常或异常,用http状态码
* 业务层:业务正常或异常,用自定义状态码
*/
// 请求成功
(res) => {
LoadingBar.stop();
// HTTP 状态码
if (res.status !== 200) {
return Promise.reject(res);
}
// 业务状态码
let code = res.data.code;
if (!code || code === 2000) {
// 无code,则请求的是html页面;有code,则返回请求的数据
return Promise.resolve(res.data);
}
errorHandle(code, res.data.msg);
return Promise.reject(false);
},
// 请求失败
(error) => {
LoadingBar.stop();
const { response } = error;
if (response) {
// 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.message);
return Promise.reject(response);
} else {
tip("网络出现故障,请稍后再试");
}
}
);
5. 错误处理
/**
* 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码
*/
const errorHandle = (status, msg) => {
// 状态码判断
switch (status) {
// 2002: 用户名/密码错误
case 2002:
tip('用户名或密码错误!')
break
// 4003: token过期,清除token并跳转登录页
case 4003:
toLogin("登录信息过期")
break
// 其他状态码
...
default:
tip('后台维护中,请稍后再试')
}
}
/**
* 提示函数
*/
const tip = msg => {
// 使用UI框架自带的错误弹框即可
Vue.prototype.$msg.error(msg)
}
/**
* 跳转登录页
* 携带当前页面路由,以便在登录完成登录后返回当前页面
*/
const toLogin = async (msg) => {
// 移除token、用户信息
// 跳转登录页
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
})
}
三、使用 axios
1. 创建 api 接口
以user
模块为例,在src
目录下新建api
文件夹,用来存放项目的所有接口请求,新建user.js
,代码如下:
import axios from '@/utils/request'
/**
* @description: 用户登录
* @param {String} username 用户名
* @param {String} password 密码(aes加密)
*/
export const userLogin = params => {
return axios.post('/user/login', params)
}
// 其他user接口
...
2. 在页面使用
import { userLogin } from "@/api/user";
userLogin({
username: this.username,
password: this.password, // 记得加密QAQ
}).then((res) => {
this.$msg.success("登录成功");
});
四、api 进阶
很多项目都是通过以上方式来调用接口的,但是这种方式有个弊端,在每个页面都得引入需要的 API,如果某个界面用到不同模块的接口,得引入好几次,造成代码冗余。
在 B 站自学的时候,发现了一个更合适的方法,下面就来详细讲解一下。
1. 创建 api 接口
将user
模块作为一个整体导出。
import axios from '@/utils/request'
export const user = {
/**
* @description: 用户登录
* @param {String} username 用户名
* @param {String} password 密码(aes加密)
*/
userLogin(params) {
return axios.post('/user/login', params)
}
// 其他user接口
...
}
2. 创建 index.js
在使用 api 时,经常需要import
或export
各种模块,那么有没有什么办法可以简化这种操作呢?答案是肯定的,下面就为大家介绍一下require.context
的基本使用方法:
require.context(directory,useSubdirectories,regExp),三个参数分别如下:
- directory 要查找的文件路径
- useSubdirectories 是否查找子目录
- regExp 要匹配文件的正则
具体使用方式见:webpack 中 require.context 的作用require.context
官网地址:webpack-requirecontext
本案例使用如下,将所有index.js
同级 api 导入,导入后统一导出,最后在main.js
将所有 api 挂载到vue
中
// 批量导出文件
const requireApi = require.context(
// api 目录的相对路径
".",
// 是否查询子目录
false,
// 查询文件的一个后缀
/.js$/
);
let module = {};
requireApi.keys().forEach((key, index) => {
if (key === "./index.js") return;
Object.assign(module, requireApi(key));
});
export default module;
3. 引入及使用
在main.js
引入所有 api
import Vue from 'vue'
import api from '@/api'
Vue.prototype.$api = api
...
使用
this.$api.user.userLogin().then((res) => {
// 接口响应成功后的一些处理...
});
五、总结
完结撒花 😁😁😁