Axios 实用封装
Axios 在 vue 官方推荐后被越来越多的人使用,但是不得不说在项目直接使用 axios 实在是繁琐,每次都要写一堆的配置,而且将配置写在业务代码中十分地不雅,一般在项目中使用的时候都会将其再次封装,以便更好的使用。但是在网上找了一圈,都没发现让我满意的方案,不是不优雅,就是根本不实用。于是我自己实现了个简单但是非常实用的封装。
实现思路
我个人理想中的请求方案如下:
- 实际请求与请求配置解耦
- 请求配置可配置
- 请求配置集中管理
- 请求配置去『中心化』
可能你们会问,什么叫集中管理但去『中心化』集中管理不难理解,但是如果集中到一个文件的话,可能项目初期并没有什么问题,但是一旦项目做大了,这个文件对于维护者来说简直就是灾难,所以需要将一个文件分成多个文件『集中』管理。
但是划分的规则是什么?以功能模块划分。这个在我们公司的项目中已经有了很好的实践,以下是文件结构:
.
├── src
| ├── modules
| | ├── module1
| | | ├── apis.js
| | | └── ...
| | ├── module2
| | | ├── apis.js
| | | └── ...
| | └── ...
| ├── api.js
| └── ...
└── ...
我们的封装就 写在 src/api.js
文件中。
添加 axios 基本配置
具体配置项的意思这里就不写了,详见官网。baseURL
可根据公司的情况和环境变量来注入不用的值。
import Axios from 'axios';
export const axios = Axios.create({
baseURL: process.env.VUE_APP_API_BASIC_URL,
responseType: 'json',
// withCredentials: true,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
validateStatus: status => ((status >= 200 && status < 300) || status === 304)
});
添加请求拦截器
请求拦截器中可以做一些骚操作,这里就简单地添加 token
。
Axios.interceptors.request.use(
config => {
/*FIXME*/
// 此处根据公司情况替换获取 token 的方式
const token = "xxx";
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => Promise.reject(error);
);
获取不同模块下的 apis
require.context
是 webpack 动态引入文件的方法,如果你们公司不使用 webpack 进行打包,可使用 node 的 fs
模块。require.context
具体的使用方式见 webpack 官网
let apisConfig = {};
const apis = {};
const context = require.context(`./modules`, true, /apis\.js$/);
context.keys().forEach(key => {
const {default: api} = context(key);
apisConfig = Object.assign(apisConfig, api);
});
封装发送请求方法
直接上代码:
Object.keys(apisConfig).forEach(key => {
const config = apisConfig[key];
/**
* 实际发送请求的方法
* @param restful restful 参数
* @param params 请求参数
* @return {Promise<AxiosResponse<T>>}
*/
function request(restful, params) {
config.method = config.method || 'get';
let parameter = {};
let query = {};
if (config.restful) {
const match = config.url.match(/{[^{}]+}/g);
if (!config.transform) {
if (match && match.length > 0) {
match.forEach(str => {
str = str.slice(1, -1);
if (!restful || Object.prototype.toString.call(restful) !== '[object Object]' || !Object.keys(restful).includes(str)) {
let cancel;
config.cancelToken = new CancelToken(c => cancel = c);
cancel(`${key} 请求中 ${str} 参数未注入`);
} else {
config.url = config.url.replace(`{${str}}`, restful[str]);
}
});
config.transform = true;
} else {
let cancel;
config.cancelToken = new CancelToken(c => cancel = c);
cancel('你似乎并不需要 restful,请删除 restful 属性,或赋值为 false');
}
}
parameter = params;
query = arguments[2];
} else {
parameter = restful;
query = arguments[1];
}
if (config.method === 'get' || config.method === 'delete') {
config.params = {...parameter, ...query};
} else if (config.method === 'post' || config.method === 'put' || config.method === 'patch') {
config.data = parameter;
config.params = query;
}
return axios.request(config);
}
apis[key] = request;
});
这里解决一个痛点:axios 不支持 restful。至少我翻了官网没看到有支持 restful,如果有哪位大佬知道 axios 原生支持 restful 的方法,请评论或邮件指导,感谢。
完整代码
完整代码可以看我的 github 上的项目。
如何使用
1. 编写请求配置
在各个模块下的 apis.js
文件中写入以下配置:
export default {
getTest: {
// 请求的 url
url: '/user/{id}',
// 请求的方式,默认是 get 方式,可不写
method:'get'
// 是否支持 restful
restful: true
},
如果有请求的域名和基本配置中的不一致的,可以使用绝对 URL,记得带上网络协议
2. 引入封装后的 axios
在 main.js
中引入,并添加到 window 对象上,这样就可以全局使用了
import api from './api';
window.api = api;
3. 发送请求
使用 window.api
window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}).then((data: any) => {
console.log(data);
}).catch((e: any) => {
Promise.reject(e);
});
4. 让请求更加 hack
虽然使用 Promise
可以简单地获取数据和捕获错误,但是如果使用 ES7
中的 async
函数却不得不 try/catch
,这里使用大佬的提供一个更加 hack 的方式,详见 How to write async await without try-catch blocks in Javascript
async getTestData() {
const [error, data] = await to(window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}));
if(error){
...
}
...
}
最后
由于本人经验尚浅,可能存在一些 bug,如果发现请及时提出,与君共勉,谢谢。
欢迎转载,转载请注明出处:https://blog.kaguramea.me/archives/axios-encapsulation
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。