Axios
是vue项目
中使用最多的一个第三方开源免费的HTTP库
,最大的特点在于可以同时兼容浏览器端和NodeJS
服务端。底层通过判定不同的运行环境来自动提供不同的适配器,在浏览器端通过原生的XHR
对象来发送请求,而在NodeJS
服务端则通过内置的http模块
来发送请求。
1、基础示例
1 // 安装 axios 2 npm install --save axios; 3 4 // 导入 axios 5 import axios from 'axios'; 6 // 创建 axios 实例 7 const instance = axios.create({ 8 baseURL: 'https://www.some-domain.com/path/to/example', 9 timeout: 30000, 10 headers: { 11 'Content-Type': 'application/x-www-form-urlencoded', 12 }, 13 }); 14 // 设置 axios 实例默认配置 15 instance.defaults.headers.common['Authorization'] = ''; 16 instance.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'; 17 18 // 自定义请求拦截器 19 instance.interceptors.request.use(config => { 20 const token = window.localStorage.getItem('token'); 21 token && (config.headers['Authorization'] = token); 22 return config; 23 }, error => Promise.reject(error)); 24 25 // 自定义响应拦截器 26 instance.interceptors.response.use(response => { 27 if (response.status === 200) { 28 return Promise.resolve(response.data); 29 } 30 31 return Promise.reject(response); 32 }, error => Promise.reject(error));
2、结合Axios
提供的CancelToken
构造函数来创建一个简单的post请求
1 const CancelToken = axios.CancelToken; 2 let cancel; 3 4 instance.post('/api/user/123', { 5 name: 'new name', 6 phone: 'new phone', 7 }, { 8 // CancelToken 构造函数接收一个 executor 函数参数,并且该函数接收一个取消函数 c 用于取消该次请求 9 cancelToken: new CancelToken(function executor(c) { 10 // 将取消函数赋值到外部变量,方便从外部取消请求 11 cancel = c; 12 }), 13 }); 14 15 // 手动取消请求 16 cancel();
3、为了避免在每个请求中都需要手动去实例化CancelToken
,我们可以巧妙利用request拦截器
来整合这部分的逻辑,实现逻辑复用
3.1、首先将缓存逻辑拆分到一个单独的文件中:
1 // cacheUtils.js 2 export const CacheUtils = { 3 // 存储请求接口地址以及请求体和取消函数之间的映射关系 4 cache: {}, 5 6 // 根据提供的键名 key 取消对应的请求,若未提供则取消全部请求 7 clearCache: function (key) { 8 if (key) { 9 const cancel = this.cache[key]; 10 if (cancel && typeof cancel === 'function') { 11 cancel(); 12 delete this.cache[key]; 13 } 14 15 return; 16 } 17 18 Object.keys(this.cache).forEach(cacheKey => { 19 const cancel = this.cache[cacheKey]; 20 cancel(); 21 delete this.cache[cacheKey]; 22 }); 23 }, 24 };
3.2、接下来将其应用到请求拦截器和响应拦截器中:
1 import qs from 'qs'; 2 import { CacheUtils } from './cacheUtils.js'; 3 4 // 自定义请求拦截器 5 instance.interceptors.request.use(config => { 6 let cacheKey = config.url; 7 8 const token = window.localStorage.getItem('token'); 9 token && (config.headers['Authorization'] = token); 10 11 const method = config.method.toLowerCase(); 12 if (method === 'get' && config.params && typeof config.params === 'object') { 13 cacheKey += qs.stringify(config.params, { addQueryPrefix: true }); 14 } 15 16 if (['post', 'put', 'patch'].includes(method) && config.data && typeof config.data === 'object') { 17 config.data = qs.stringify(config.data); 18 cacheKey += `_${qs.stringify(config.data, { arrayFormat: 'brackets' })}`; 19 } 20 21 // 每次发送请求之前将上一个未完成的相同请求进行中断 22 CacheUtils.cache[cacheKey] && CacheUtils.clearCache(cacheKey); 23 24 // 将当前请求所对应的取消函数存入缓存 25 config.cancelToken = new axios.CancelToken(function executor(c) { 26 CacheUtils.cache[cacheKey] = c; 27 }); 28 29 // 临时保存 cacheKey,用于在响应拦截器中清除缓存 30 config.cacheKey = cacheKey; 31 32 return config; 33 }, error => Promise.reject(error)); 34 35 // 自定义响应拦截器 36 instance.interceptors.response.use(response => { 37 // 响应接收之后清除缓存 38 const cacheKey = response.config.cacheKey; 39 delete CacheUtils.cache[cacheKey]; 40 41 if (response.status === 200) { 42 return Promise.resolve(response.data); 43 } 44 45 return Promise.reject(response); 46 }, error => { 47 // 响应异常清除缓存 48 if (error.config) { 49 const cacheKey = error.config.cacheKey; 50 delete CacheUtils.cache[cacheKey]; 51 } 52 53 return Promise.reject(error); 54 });
3.3、同样提供CacheUtils.clearCache
函数来应对需要手动清除未完成请求的应用场景,使用方式:
1 // 网页卸载前清除缓存 2 window.addEventListener('beforeunload', () => CacheUtils.clearCache(), false); 3 4 // Vue 中路由跳转前清除缓存 5 router.beforeEach((to, from, next) => { CacheUtils.clearCache(); next(); });