送人玫瑰,手有余香,你是什么,你的世界就是什么💡
前言
网络上与axios相关的教程、以及源码解析有很多,还有健全的官方文档,本篇文章面向于初学axios库的开发者,目标是快速上手,如果觉得本篇文章帮助到了你,也就达到了这篇文章的目的😊
安装依赖
本文中使用的是Vue CLI3.0,安装依赖使用vue add命令进行
- axios安装
vue add axios # yarn | npm安装 yarn add axios | npm install axios
- 引用插件执行add命令后,CLI会自动帮我们在main.js中引用它,并做一些默认配置。接下来,带大家看一下,add命令都做了哪些事情
- src下新建了一个plugins文件夹,这个文件夹用于存放Vue引入插件的相关配置文件
- 在plugins文件夹中,新建了axios.js文件
- 在package.json文件中添加了axios的依赖信息以及版本号(yarn | npm安装时会自动做这一步)
- main.js中导入了axios的配置文件,方便全局使用axios
- 使用插件
this.axios.${方法名}.then().catch() // 例子 this.axios.get(url,requestData).then((res)=>{ // 成功的回调 }).catch((err)=>{ // 失败的回调 }); /* 支持所有http请求以及请求取消、并发请求等功能,更多细节以及使用方法移步官方文档 文档: [axios文档](http://www.axios-js.com/zh-cn/docs/) */
配置axios
接下来回到本文的重点,如何去合理的配置它以提高开发效率。本篇配置基于脚手架创建的axios.js进行修改
- 创建配置文件如果使用脚手架进行安装axios,将会在在src目录下查找plugins文件夹,并在plugins文件夹下创建axios.js文件。如果使用yarn方式安装,请手动创建plugins文件夹以及对应的js文件。
- 配置文件代码
"use strict"; import Vue from 'vue'; import axios from "axios"; import store from '../store/index'; let config = { // baseURL在此处省略配置,考虑到项目可能由多人协作完成开发,域名也各不相同,此处通过对api的抽离,域名单独配置在base.js中 // 请求超时时间 timeout: 60 * 1000, // 跨域请求时是否需要凭证 // withCredentials: true, // Check cross-site Access-Control heards:{ get:{ 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' // 将普适性的请求头作为基础配置。当需要特殊请求头时,将特殊请求头作为参数传入,覆盖基础配置 }, post:{ 'Content-Type': 'application/json;charset=utf-8' // 将普适性的请求头作为基础配置。当需要特殊请求头时,将特殊请求头作为参数传入,覆盖基础配置 } }, // 在向服务器发送请求前,对数据进行处理,axios默认会序列化数据 // transformRequest:[function(data){ // // }], // 在传递给 then/catch 前,修改响应数据 // transformResponse:[function(data){ // // }] }; /** * 请求失败后的错误统一处理,当然还有更多状态码判断,根据自己业务需求去扩展即可 * @param {Number} status 请求失败的状态码 */ const errorHandle = (status, other) => { // 状态码判断 switch (status) { // 401: 未登录状态,跳转登录页 case 401: // 跳转登录页 break; // 403 token过期 case 403: // 如果不需要自动刷新token,可以在这里移除本地存储中的token,跳转登录页 break; // 404请求不存在 case 404: // 提示资源不存在 break; default: console.log(other); }}; // 创建实例 const _axios = axios.create(config); // 请求拦截器 _axios.interceptors.request.use( function(config) { // 从vuex里获取token const token = store.state.token; // 如果token存在就在请求头里添加 token && (config.headers.token = token); return config; }, function(error) { // Do something with request error error.data = {}; error.data.msg = "服务器异常"; return Promise.reject(error); } ); // 响应拦截器 _axios.interceptors.response.use( function(response) { // 清除本地存储中的token,如果需要刷新token,在这里通过旧的token跟服务器换新token,将新的token设置的vuex中 if(response.data.code===401){ localStorage.removeItem("token"); } // 只返回response中的data数据 return response.data; }, function(error) { if(error){ // 请求已发出,但不在2xx范围内 errorHandle(error.status,error.data.msg); return Promise.reject(error); }else{ // 断网 return Promise.reject(error); } } ); // eslint-disable-next-line no-unused-vars Plugin.install = function(Vue, options) { Vue.axios = _axios; window.axios = _axios; Object.defineProperties(Vue.prototype, { axios: { get() { return _axios; } }, $axios: { get() { return _axios; } }, }); }; Vue.use(Plugin); // 导出插件和_axios export default {Plugin,_axios};
- 在入口文件中进行引用
// main.js import './plugins/axios'
这里进行全局引用的原因:Vue脚手架推荐的使用方法,方便全局使用this.axios来访问。通过配置项创建 axios 实例的方式进行配置封装。最后将其导出并挂载到 Vue 的原型上即可,此时,每次修改 axios 配置,只需要修改对应的文件即可,不会影响到不相关的功能
- 小结
现在给大家梳理下,我们对配置文件做了那些封装
- 设置超时时间
- 请求头的集中配置
- 响应失败后对状态码进行统一处理
- 在请求拦截中添加token
- 在响应拦截中对token过期进行相应处理
- api抽离
- 接口域名抽离
抽离API和域名接口
为什么要进行API抽离?假设我们所有的请求都在业务代码中写this.$axios.get(),后期接口变更、有新的需求要多传参数过去,我们就要去业务代码里一个个去找然后进行修改,那将是一件很头疼的事。接下来带大家来实现API分离😃
- 在src下创建api文件夹,创建index.js和base.js
- api统一出口:index.js
将api接口根据功能划分为多个模块,利于多人开发,一个人负责一个模块的开发,方便日后接口的变更,将所有模块在此处引入,将引用暴露出去,然后挂载到Vue原型既可通过this.$api.模块名.方法名进行引用
/** * api统一出口 * */ // 网站管理接口 import websiteManageAPI from './websiteManageAPI'; // 其他模块接口 // 导出接口 export default { websiteManageAPI, // ... }
- 模块文件:websiteManageAPI.js
推荐命名格式为:模块名+APi,此文件用于将当前模块下的所有请求封装成对象,在使用时直接调用即可
/* * 网站管理接口 * */ import services from '../plugins/axios' import base from './base'; // 导入接口域名列表 const websiteManageAPI = { // 登录 login(params){ return services._axios.post(`${base.lk}/login`,params); }, // 测试post接口 postJSON(params){ return services._axios.post(`${base.lk}/getter/postJSON`,params); }, // 测试get接口 getJSON(pageNo,pageSize){ return services._axios.get(`${base.lk}/getter/getJSON`,{params:{pageNo:pageNo,pageSize:pageSize}}); } }; export default websiteManageAPI;
- 接口域名文件:base.js
将每个开发者的接口地址封装成对象,在模块中进行引用时域名遇到变更,可直接修改此处的配置文件,快速修改为变更后的域名。
/* * 接口域名管理 * * */ const base = { lk:"https://www.kaisir.cn/user", other:"https://kf.kaisir.cn/api" }; export default base;
- 原型挂载
将暴露出来的接口挂载到原型上,可方便接口的调用,当然你也可以按需加载,用到哪个模块的接口在在哪个模块下进行引用。
// 挂载到原型(main.js) Vue.prototype.$api = api;
实际应用
例如这样一个场景:后端的所有接口都需要登录后,根据成功登录返回的token进行访问。后端接口使用shiro+jwt实现接口鉴权和token发放
- 页面加载时,从本地存储中获取token
// App.vue,created生命周期 const token = localStorage.getItem("token");
- 判断token是否存在,如果不存在则获取
// if(lodash.isEmpty(token)){ // 跳转登录页:此处仅用于演示,用户名和密码为固定数据,实际需求为跳转登录页面进行授权 const userInfo = { "username":"测试", "password":"0x89oikklsa" }; // 调用登录api this.$api.websiteManageAPI.login(userInfo).then((res)=>{ // 将token进行存储并更新到vuex中 localStorage.setItem("token",res.token); this.$store.state.token = res.token; }); }else{ // 更新vuex中的token this.$store.state.token = token; }
- 执行结果
- 调用其他接口,测试请求头token是否添加成功
// 测试其他接口能否调用成功 this.$api.websiteManageAPI.getJSON(1,3).then((res)=>{ console.log("接口调用成功"); console.log(res) }); }
- 执行结果
写在最后
- 文中如有错误,点击下方阅读原文,在评论区留言,如果这篇文章帮到了你,欢迎点赞和关注😊