Axios 在 vue 官方推荐后被愈来愈多的人使用,可是不得不说在项目直接使用 axios 实在是繁琐,每次都要写一堆的配置,并且将配置写在业务代码中十分地不雅,通常在项目中使用的时候都会将其再次封装,以便更好的使用。可是在网上找了一圈,都没发现让我满意的方案,不是不优雅,就是根本不实用。因而我本身实现了个简单可是很是实用的封装。javascript
我我的理想中的请求方案以下:vue
可能大家会问,什么叫集中管理但去『中心化』集中管理不难理解,可是若是集中到一个文件的话,可能项目初期并无什么问题,可是一旦项目作大了,这个文件对于维护者来讲简直就是灾难,因此须要将一个文件分红多个文件『集中』管理。java
可是划分的规则是什么?以功能模块划分。这个在咱们公司的项目中已经有了很好的实践,如下是文件结构:node
. ├── src | ├── modules | | ├── module1 | | | ├── apis.js | | | └── ... | | ├── module2 | | | ├── apis.js | | | └── ... | | └── ... | ├── api.js | └── ... └── ...
咱们的封装就 写在 src/api.js
文件中。webpack
具体配置项的意思这里就不写了,详见官网。baseURL
可根据公司的状况和环境变量来注入不用的值。ios
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
。git
Axios.interceptors.request.use( config => { /*FIXME*/ // 此处根据公司状况替换获取 token 的方式 const token = "xxx"; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => Promise.reject(error); );
require.context
是 webpack 动态引入文件的方法,若是大家公司不使用 webpack 进行打包,可以使用 node 的 fs
模块。require.context
具体的使用方式见 webpack 官网github
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); });
直接上代码:web
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 的方法,请评论或邮件指导,感谢。json
完整代码能够看个人 github 上的项目。
在各个模块下的 apis.js
文件中写入如下配置:
export default { getTest: { // 请求的 url url: '/user/{id}', // 请求的方式,默认是 get 方式,可不写 method:'get' // 是否支持 restful restful: true },
若是有请求的域名和基本配置中的不一致的,可使用绝对 URL,记得带上网络协议
在 main.js
中引入,并添加到 window 对象上,这样就能够全局使用了
import api from './api'; window.api = api;
使用 window.api
window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}).then((data: any) => { console.log(data); }).catch((e: any) => { Promise.reject(e); });
虽然使用 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