Axios 在 vue 官方推荐后被越来越多的人使用,但是不得不说在项目直接使用 axios 实在是繁琐,每次都要写一堆的配置,而且将配置写在业务代码中十分地不雅,一般在项目中使用的时候都会将其再次封装,以便更好的使用。但是在网上找了一圈,都没发现让我满意的方案,不是不优雅,就是根本不实用。于是我自己实现了个简单但是非常实用的封装。 实现思路我个人理想中的请求方案如下:
可能你们会问,什么叫集中管理但去『中心化』集中管理不难理解,但是如果集中到一个文件的话,可能项目初期并没有什么问题,但是一旦项目做大了,这个文件对于维护者来说简直就是灾难,所以需要将一个文件分成多个文件『集中』管理。 但是划分的规则是什么?以功能模块划分。这个在我们公司的项目中已经有了很好的实践,以下是文件结构: . ├── src | ├── modules | | ├── module1 | | | ├── apis.js | | | └── ... | | ├── module2 | | | ├── apis.js | | | └── ... | | └── ... | ├── api.js | └── ... └── ... 我们的封装就 写在 添加 axios 基本配置具体配置项的意思这里就不写了,详见官网。 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) }); 添加请求拦截器请求拦截器中可以做一些骚操作,这里就简单地添加 Axios.interceptors.request.use( config => { /*FIXME*/ // 此处根据公司情况替换获取 token 的方式 const token = "xxx"; if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, error => Promise.reject(error); ); 获取不同模块下的 apis
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. 编写请求配置在各个模块下的 export default { getTest: { // 请求的 url url: '/user/{id}', // 请求的方式,默认是 get 方式,可不写 method:'get' // 是否支持 restful restful: true }, 如果有请求的域名和基本配置中的不一致的,可以使用绝对 URL,记得带上网络协议 2. 引入封装后的 axios在 import api from './api'; window.api = api; 3. 发送请求使用 window.api.getTest({userId: 1, id: 2}, {name: 'Tom'}).then((data: any) => { console.log(data); }).catch((e: any) => { Promise.reject(e); }); 4. 让请求更加 hack虽然使用 async getTestData() { const [error, data] = await to(window.api.getTest({userId: 1, id: 2}, {name: 'Tom'})); if(error){ ... } ... } 最后由于本人经验尚浅,可能存在一些 bug,如果发现请及时提出,与君共勉,谢谢。 |
|
来自: python_lover > 《待分类》