前言

看了网上很多axios的封装,感觉都不是特别完善。于是我写了个比较完整的封装包括以下功能:

  1. 上传下载文件时的header设置
  2. 错误相应的统一处理
  3. 动态加载api
  4. 数据缓存、清除缓存、缓存级别、最大缓存数
  5. 拦截重复请求、页面跳转时取消正在请求

( 刷新token逻辑可以看这个,刷新token并没有在下面的代码中实现,因为我不知道后台node要怎么刷新token)暂时就想到这些,如果有其他想法可以留言给我

一、安装插件并引入

npm install axios --save
npm install vue-router --save
npm install nprogress --save
npm install element-ui --save
npm install crypto-js --save
import axios from 'axios'
import router from './router'
import NProgress from 'nprogress'
import { Message } from 'element-ui'
import HmacMd5 from 'crypto-js/md5'

二、创建一个新的axios

const service = axios.create({// 设置基础url,拼接规则是  代理的url + 基础url + 请求时的urlbaseURL: '/api',// 设置请求超时时间timeout: 20000,headers: {'content-type': 'application/json', // 设置请求体类型/*常用的请求格式有:'application/json': 发送JSON对象'multipart/form-data': 需要文件上传时,就使用该格式根据后台需求发送其他需要放在header里面数据,例如:'Authorization': 'Basic ****', //登录验证*/},// 默认情况下,后台状态码不返回200的话,是不会收到返回数据的,可以根据需要设置后台返回状态码的区间validateStatus: function(status) {return status >= 200 && status <= 500;},// 请求时是否携带cookie信息withCredentials: true,
})

三、HTTPrequest拦截和HTTPresponse拦截

//HTTPrequest拦截
service.interceptors.request.use(config => {NProgress.start() // start progress bar// 一般我们上传文件都是使用form表单,所以这里判断下data是否是form对象,从而改变请求类型if (config.data instanceof FormData) {config.headers['content-type'] = 'multipart/form-data';}let token = localStorage.getItem('token');if (token) {config.headers['Authorization'] = token; // 让每个请求携带token--['Authorization']为自定义key 请根据实际情况自行修改}// 如果请求的接口返回一个文件,需要我们将responseType设置为blob// if (config.url.indexOf('/file/downLoad') != -1) {//     config.responseType = 'blob';// }return config
}, error => {return Promise.reject(error)
});//HTTPresponse拦截
//客户没有连网、网速慢导致超时,这两种情况不会调用response,需要在请求的.catch中处理
service.interceptors.response.use(res => {NProgress.done();//如果是401则跳转到登录页面if (res.status === 401) router.push({ path: '/login' });// 如果请求为非200否者默认统一处理if (res.status != 200) {return Promise.reject(new Error(res.statusText))}return res;
}, error => {NProgress.done();return Promise.reject(error);
})

四、创建缓存对象

// 缓存对象
let cache = {// 缓存列表list: [],// 最大缓存数MAXCACHE: 5,add(data) {// 根据缓存级别计算时间戳// 如果没有设置level为0,这里的逻辑相当于每10分钟级别下降一级data.timestamp = Number(item.level || 0) * (1000 * 60 * 10) + new Date().getTime();// 根据时间戳大小判断缓存插入位置let index = this.list.findIndex(item => {return item.timestamp ? data.timestamp < item.timestamp : true;})if (index <= 0) {this.list.unshift(data);} else {this.list.splice(index, 0, data);}if (this.list.length > this.MAXCACHE) {this.list.pop();}},find(key) {return this.list.find(item => {return key === item.key;})},deleteApiName(apiName) {this.list = this.list.filter(item => {return item.apiName !== apiName;})},clear() {this.list = [];}
};

五、创建错误处理方法

一般来说

Status Codeb不等于200的我们统一处理,

而返回体中code返回的不是200,交给页面中各自处理。

// 把常见错误消息翻译成中文让用户更容易理解,error.message我没仔细研究过,可能和你的返回内容不一致,修改即可。
// 这里处理了几种常见的错误提示,请求不到服务器、客户没有连网、网速慢导致超时。
const error_toast = (error) => {switch (error.message) {case 'Internal Server Error':Message.error('服务器升级中,请稍后再试');break;case 'Network Error':Message.error('请求失败,请检查您的网络');break;case (/timeout/.test(error.message) ? error.message :false):Message.error('请求超时,请稍后重试');break;default:Message.error(error.message || '请求失败');}}

六、监听页面跳转

let now_path = '/';
// 监听页面跳转
router.beforeEach((to, from, next) => {now_path = to.fullPath; // 纪录当前页面路径,for (let item in request_list) {// 页面跳转时是否取消请求,使用场景:有些页面中会请求大量数据,且在其他页面中没有相同的接口时应取消请求、// 字典类接口在多个页面中都有使用跳转页面时不应取消请求,这样在下一个页面中就可以直接使用缓存内容;if (request_list[item].isSkipCancel) {// 取消请求request_list[item].cancel('pageTurn');// 删除请求中的keydelete request_list[item];}}next();
})

七、创建请求方法

// 定义一个正在请求的列表,用来防止重复请求
let request_list = {};
// 用来在跳转页面时取消重复请求
const CancelToken = axios.CancelToken;const request = (params, apiName) => {// key可以用来判断请求的url、参数是否完全相同let key = params.url + HmacMd5(JSON.stringify(params.params) + JSON.stringify(params.data)).toString();console.log(`生成当前请求的key为${key}`);if (request_list[key]) {console.log(`当前请求已在请求列表中`);if (now_path != request_list[key].path) {console.log(`请求为不同页面发起,请求成功后返回数据`);return new Promise((resolve, reject) => {request_list[key].promise_list.push({ resolve, reject });})} else {console.log(`请求为相同页面发起,直接返回错误`);return Promise.reject({code: 301,msg: '请求中,请稍等',});}} else if (cache.find(key) !== undefined) {console.log('有缓存,直接返回数据');return Promise.resolve(cache.find(key).response_data);} else {return new Promise((resolve, reject) => {console.log('没有缓存,发起请求', params);// 将api名称、当前页面路径、页面跳转时是否取消请求,这些都加到request_list对应的key中request_list[key] = { apiName, path: now_path, isSkipCancel: params.isSkipCancel | false, };params.cancelToken = new CancelToken(function executor(c) {// 获取到取消请求的方法request_list[key].cancel = c;})// 把回调方法也放进来request_list[key].promise_list = [{ resolve, reject }];service(params).then(res => {console.log('返回请求', res.data);request_list[key].promise_list.map(item => {item.resolve(res.data);})if (params.method !== 'get') {console.log(`请求不是get请求,删除同一个名称的缓存数据`);// 例如:加了一个用户,这时应该删除用户列表的缓存,下次get请求时加载最新的用户列表cache.deleteApiName(apiName);} else if (params.isCache || params.isCache === undefined) {console.log(`请求是get请求,缓存返回数据`);// 添加缓存cache.add({response_data: res.data,key,apiName,level: params.level,})}console.log(`请求完成,在请求列表中删除对应的key`);delete request_list[key];}).catch(err => {if (err.message !== "pageTurn") {request_list[key].promise_list.map(item => {item.reject(err);})console.log(`请求错误,在请求列表中删除对应的key,并根据错误显示提示框`);delete request_list[key];error_toast(err);} else {console.log('请求取消');}})})}
}

八、动态加载API

请求每次使用时都需要先import对应的文件,比较麻烦;

// 引入
import { add } from "@/api/tool/code";
// 在方法中
add()

这样做的好处就是不用在一开始就加载大量的api,不好的地方是每个页面都需要手动引入,尤其是一些比较通用的接口上,要再好多界面中引入。

利用Proxy对象可以实现api的自动加载,当然Proxy还可以用一些公用方法上,访问对象方法时自动加载。

let api = {};
api = new Proxy(api, {// apiName是访问api下的对象名称也作为文件名称和文件里所有api的名字,在数据缓存中有相关处理get(target, key) {if (target[key] === undefined) {//在访问api的属性是判断是否有这个属性没有的话就按照名字和固定的路径去加载文件,然后挂载上去,最后返回console.log(`没有属性,根据key'${key}'添加`);//加载路径可以根据自己的api放置位置和规则修改let obj = require('./api/' + key + '.js').default;target[key] = {};for (let item in obj) {target[key][item] = (data) => {return request(obj[item](data), key);}}// 添加一个清空这个文件中接口缓存的方法,使用场景:页面内的刷新按钮,小程序、公众号的下拉刷新target[key].$clear = cache.deleteApiName(key);}return target[key];}
})// 添加一个清空所有缓存的方法,使用场景: 退出登录
api.$clear = cache.clear();export default api; //这里导出,最后挂载到全局

九、API封装文件

let user = {get: ({ current, size }) => {return {url: '/user',method: 'get',isCache: true, // 是否缓存,不写默认为缓存level: 0, // 缓存级别params: { current, size }}},post: (data) => {return {url: '/user',method: 'post',data: {name: data.name,age: data.age}}},put: ({ id, name, age }) => {return {url: '/user',method: 'put',data: { id, name, age },}},delete: ({ id }) => {return {url: '/user',method: 'delete',params: { id: id },}}
}export default user;

十、页面中调用

this.$api.user.get({}).then((res) => {});

axios封装 —— 数据缓存、防止重复请求、动态加载相关推荐

  1. 异步请求动态加载页面

    最近现在在做的项目需要前后端分离,并且还有一些国际化的原因,需要动态替换页面上的一些元素,我简单的和前端同学说了一下我的思路,但是前端同学貌似没太明白,于是自己写了个demo. 大致思路是这样的:先从 ...

  2. ajax 技术动态加载数据,jQuery结合Ajax实现动态加载数据【原创】

    原先的页面如下: 要实现的效果图: 要实现的效果,就是点击"查看更多"按钮,动态加载五条数据.而点击"查看所有"时数据全部加载. 主要的思路: 1.点击按钮,发 ...

  3. python调用js获取异步返回的数据_Python怎么获取js动态加载的数据

    展开全部 import selenium from selenium import webdriver from selenium.common.exceptions import NoSuchEle ...

  4. HelloChart框架动态加载数据

    HelloChart框架动态加载数据 之前使用MPAndroidChart做过一个动态加载数据的折线统计图,完成如下功能: 一个动态加载数据的图表,首次进入加载20条,并且视图显示在最右边,然后滑动到 ...

  5. jQuery动态加载select下拉列表

    需求说明: 以前使用的select下拉列表都是静态的,select 的option数据都是写死的.现在项目中的select需要根据不同的场景使用不同的数据,解决方式就是动态加载option数据. 代码 ...

  6. jQuery写的一棵动态加载的树

    一个棵自己写的jQuery的树.与大家分享一下. 主要用于动态加载子节点,避免大数据量加载页面慢的情况. 展示效果: 下面贴上源码: css部分: #TreeView {     width:100% ...

  7. python爬虫之动态加载获取药品监督管理局

    本次爬取实现使用request模块爬取国家药品监督管理局的企业信息数据并存入到Excel表格中 爬取目标网站 http://scxk.nmpa.gov.cn:81/xk/# 分析页面: 打开网页查看首 ...

  8. Day239.RBAC模式、动态加载用户权限资源规则数据规则、【记住我】注销多次登录图片验证码session验证码验证功能 -springsecurity-jwt-oauth2

    1.RBAC权限管理模型 一.RBAC权限模型简介 RBAC权限模型(Role-Based Access Control)即:基于角色的权限控制.模型中有几个关键的术语: 用户:系统接口及功能访问的操 ...

  9. vue 动态修改后端请求_vue-element-admin实战 | 第二篇: 最小改动接入后台实现根据权限动态加载菜单...

    一. 前言 本篇基于 有来商城 youlai-mall微服务项目,通过对vue-element-admin的权限菜单模块理解个性定制其后台接口,实现对vue-element-admin工程几乎不做改动 ...

最新文章

  1. Programming Principles and Practice Using C++ Notes1
  2. 来篇文章:Martin Fowler的设计已死中文版
  3. android ota更新app,企业 OTA 更新  |  Android 开源项目  |  Android Open Source Project
  4. 10恢复出厂设置_笔记本电脑怎么恢复出厂设置
  5. DNS如何查找IP?
  6. JFFS2文件系统的移植
  7. 最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程)
  8. 使用iRedMail 搭建邮件服务器
  9. 设置自定义电脑屏幕分辨率
  10. [多媒体] 10大开源视频剪辑软件
  11. 替换字符串中的英文括号为其他字符串
  12. 区块链的未来:“2020年起3-5年:国内区块链大规模商业应用将全面落地开花”
  13. 如何同时使用内网(本地有线连接)和外网(WLAN无线连接)
  14. 计算机定时关机教程,1分钟学会 如何让电脑定时关机,定时开机!
  15. 计算机教师职称申报工作总结,教师职称评定个人工作总结(精选3篇)
  16. 算法交易的成长与未来
  17. 利用三级结构进行蛋白质嵌入的自我监督预训练
  18. iscsi技术,磁盘阵列技术介绍
  19. Android Studio Dolphin Patch 1 简介及下载地址
  20. 院士:科研工作者也得养家!非升即走压力下,不得不做短平快的研究

热门文章

  1. LVGL---使用物理按键代替触摸(groups)
  2. shell 删除七日内日志_SHELL脚本定期删除日志文件(日志定期清理)
  3. QQMusic与Android studio 冲突导致Adb not reposponding
  4. 使用div和css重构网站,DIV+CSS网页重构概念详解
  5. android sql语句博客,通过SQL语句查询
  6. 质数在mysql中怎么表达_质数如何定义
  7. JAVA写HTTP代理服务器(二)-netty实现
  8. mikrotik基于官方手册学习
  9. 详解零知识证明的四大基础技术,如何与以太坊发生反应
  10. 【CodeForces 1253C --- Sweets Eating】DP