优势
1. 对原先封装好的axios实例修改的地方很少
2. 仅需新建一个文件,并引入完成相应配置即可轻松实现三大功能,全局加载动画的显示与隐藏回调、重复请求时取消前面的请求或者禁用后面的请求、实现无感知刷新accessToken。
3. 仅需将原先使用旧的axios替换为新的实例 即可轻松实现上述功能。
使用方式
1. 安装
npm install vue-axios-optimize
2. 目录结构大致如下
api目录下的modules目录为各个功能模块对应使用到的接口
index.js 负责将每个模块暴露出一个对象出去
axios.js 为创建的一个基础功能(请求baseurl,timeout,设置请求头等)的axios实例
axios-optimize.js 为引入插件包,并进行响应配置,使请求具备防止重复请求等功能
common-api.js 为具体请求的相关书写,此处引入axios-optimize暴露出来的实例作为请求的方法。
3. axios-optimize.js大致代码如下
不配置无感知刷新accessToken时,vue2项目例子大致如下
import axios from "axios"
import instance from "@/api/axios"
import AxiosOptimize from "vue-axios-optimize"
import store from "@/store"
const axiosOptimize = new AxiosOptimize(axios, instance, {
showLoadingFun: (config, requestNum) => {
store.commit("app/SET_LOADING_STATUS", true)
},
hideLoadingFun: (config, requestNum) => {
store.commit("app/SET_LOADING_STATUS", false)
}
})
export default axiosOptimize.instance
配置无感知刷新accessToken时,vue3项目例子大致如下import axios from 'axios'
import instance from '@/api/axios.js'
import AxiosOptimize from 'vue-axios-optimize'
import { useAppStoreHook } from '@/store/modules/app'
const useAppStore = useAppStoreHook()
import { useUserStoreHook } from '@/store/modules/user'
import { ElMessageBox } from 'element-plus'
const axiosOptimize = new AxiosOptimize(axios, instance, {
showLoadingFun: () => {
// 展示加载动画方法
useAppStore.setLoadingStatus(true)
},
hideLoadingFun: () => {
// 关闭加载动画方法
useAppStore.setLoadingStatus(false)
},
openRefresh: true, // 开启无感知刷新token
refreshApiUrl: '/xiaobu-admin/refresh-token', // 刷新tokenApi的 url
getRefreshTokenFun: () => {
const useUserStore = useUserStoreHook()
// 获取refreshToken
return useUserStore.gettersRefreshToken
},
reloginFun: async (response) => {
const useUserStore = useUserStoreHook()
await useUserStore.clearAuth()
ElMessageBox.alert(`${response.message}`, '提示', {
confirmButtonText: 'OK',
showClose: false,
callback: async (action) => {
if (action === 'confirm') {
// 刷新浏览器是为了 跳转登录页时query的redirect 会带上 当前页面地址
window.location.reload()
}
}
})
},
refreshTokenStore: (refreshToken) => {
const useUserStore = useUserStoreHook()
return useUserStore.refreshTokenAction({ refreshToken })
},
setAccessTokenFun: (config, accessToken) => {
// Reflect.set(config.headers, 'authorization', 'Bearer ' + accessToken)
config.headers.authorization = 'Bearer ' + accessToken
},
responseResultFun: (res) => {
// 此方法配置 返回数据 的 逻辑
if (res.config.responesType === 'blob') {
delete res.config
return res
}
if (res.code === 200) {
return res.data
}
delete res.config
return res
},
formatAccessTokenFun: (data) => {
// 此方法返回 请求接口后 返回的 accessToken
return data.accessToken
}
})
export default axiosOptimize.instance
4. axios.js大致需要注意的地方如下示例
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStoreHook } from '@/store/modules/user'
// 创建axios实例
const service = axios.create({
baseURL: '/proxy',
timeout: 10000
})
// request拦截器
service.interceptors.request.use(
(config) => {
// 一般会请求拦截里面加token
const useUserStore = useUserStoreHook()
const accessToken = useUserStore.gettersAccessToken
if (accessToken) {
config.headers['authorization'] = 'Bearer ' + accessToken
}
return config
},
(error) => {
// 这个return 一定记得 带上 否则无法使用
return Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
async (res) => {
const { config, data } = res
// code为200 直接返回有用数据 多返回一个config ...data 为接口返回的最外层数据
if (data.code === 200) {
return { ...data, config }
}
// 当项目无 无感知刷新token的功能时 此处对应code该什么逻辑就什么逻辑
// dosomething ... 如 code === 401 时 清除token 刷新页面等
// 报错时 多返回一个 报错标识 responseErr: true ...data 为接口返回的最外层数据
return { ...data, config, responseErr: true }
},
(error) => {
if (error.name === 'AxiosError') {
ElMessage({
showClose: true,
message: `${error.message},请检查网络或联系管理员!`,
type: 'error'
})
}
// 注意return 不可丢失
return Promise.reject(error)
}
)
export default service
5. common-api.js应用部分大致如下
import axiosOptimize from '@/api/axios-optimize.js'
// 需要配置 请求接口时 不加载全局动画 则 配置 noShowLoading: true
// 需要配置 重复请求时 取消前面的请求 则 配置 preventDuplicateRequestsType: "cancel"
// 需要配置 重复请求时 禁用后面的请求 则 配置 preventDuplicateRequestsType: "prevent"
// get 请求demo 1
export function getDemo1(
data = {},
config = {
noShowLoading: true, // 配置不展示加载动画
preventDuplicateRequestsType: "cancel" // 配置重复请求时 取消前面的请求
}
) {
return axiosOptimize.get(`/xiaobu-admin/getDemo1`, { params: data, ...config })
}
// get 请求 demo 2
export function getDemo2(
data = {},
config = {
preventDuplicateRequestsType: "prevent" // 配置重复请求时 后面的请求无效
}
) {
return axiosOptimize({
method: 'get',
url: `/xiaobu-admin/getDemo2`,
params: data,
...config
})
}
// post 请求demo 1
export function postDemo1(data = {}, config = {}) {
return axiosOptimize.post('/xiaobu-admin/postDemo1', data, config)
}
// post 请求demo 2
export function postDemo2(data = {}, config: UserAxiosRequestConfig = {}) {
return axiosOptimize({
url: '/xiaobu-admin/postDemo2',
method: 'post',
data,
...config
})
}
// delete 请求demo 1 使用params作为参数 参数会拼接在请求路径上
export function deleteDemo1(
data = {},
config = {
noShowLoading: true // 配置不展示加载动画
}
) {
return axiosOptimize.delete(`/xiaobu-admin/deleteDemo1`, { params: data, ...config })
}
// delete 请求 demo 2 使用params作为参数 参数会拼接在请求路径上
export function deleteDemo2(
data = {},
config = {}
) {
return axiosOptimize({
method: 'delete',
url: `/xiaobu-admin/deleteDemo2`,
params: data,
...config
})
}
// delete 请求demo 3 使用data作为参数 参数不展示在 请求路径上
export function deleteDemo3(data = {}, config = {}) {
return axiosOptimize.delete(`/xiaobu-admin/deleteDemo3`, { data, ...config })
}
// delete 请求 demo 4 使用data作为参数 参数不展示在 请求路径上
export function deleteDemo4(data = {}, config = {}) {
return axiosOptimize({
method: 'delete',
url: `/xiaobu-admin/deleteDemo4`,
data,
...config
})
}
// put 请求demo 1
export function putDemo1(data = {}, config = {}) {
return axiosOptimize.put('/xiaobu-admin/putDemo1', data, config)
}
// put 请求demo 2
export function putDemo2(data = {}, config = {}) {
return axiosOptimize({
url: '/xiaobu-admin/putDemo2',
method: 'put',
data,
...config
})
}
// patch 请求demo 1
export function patchDemo1(data = {}, config = {}) {
return axiosOptimize.patch('/xiaobu-admin/patchDemo1', data, config)
}
// patch 请求demo 2
export function patchDemo2(data = {}, config = {}) {
return axiosOptimize({
url: '/xiaobu-admin/patchDemo2',
method: 'patch',
data,
...config
})
}
6. 页面中使用时,部分情况需要注意地方如下
this.loading = true
commonApi.getUserList(this.addDateRange(this.queryParams, this.dateRange)).then(res => {
const response = res.data
this.list = response.rows
this.total = response.total
this.loading = false
}).catch(err => {
// 此处需要添加 如果是取消请求 或者是 阻止请求时 不进行操作
if (err.isPrevent || err?.message?.isCancel) {
return
}
this.loading = false
})
特别注意
由于插件使用了es6的class语法,vue2项目得配置将vue-axios-optimize编译,因此需要在vue.config.js中添加如下代码
module.exports = {
...
transpileDependencies: [
'vue-axios-optimize', // 因为使用了es6语法 因此也需要编译
],
...
}
new AxiosOptimize 参数说明
接收三个参数,按顺序分别如下
参数 | 说明 | 来源 |
---|---|---|
axios | 安装axios中的axios | import axios from 'axios' |
instance | 创建好的axios实例,已经配置好请求头等相关内容 | import instance from '@/api/axios.js' |
options | 一些配置,详情继续阅读文档 | 自定义配置 |
options 配置说明
参数 | 类型 | 说明 | 是否必传 | 默认值 |
---|---|---|---|---|
showLoadingFun(config, requestingNum) | Function | 展示动画,config为该请求的config,requestingNum为目前正在请求几个接口,此处可执行一些展示全局动画的操作 | 否 | 无 |
hideLoadingFun(config, requestingNum) | Function | 隐藏动画,config为该请求的config,requestingNum为目前正在请求几个接口,此时应该为0,此处可执行关闭全局动画的操作 | 否 | 无 |
openRefresh | Boolean | 是否开启无感知刷新token | 否 | false |
refreshApiUrl | String | 请求刷新token接口的api地址 如/xiaobu-admin/refresh-token | 当openRefresh为true时必传 | 无 |
getRefreshTokenFun() | Function | 获取当前项目的 refreshToken方法, 记得 return 回去 | 当openRefresh为true时必传 | 无 |
reloginFun(response) | Function | response 为axios实例中返回的数据,此处建议执行清除token相关缓存并弹框提示,点击确认进行刷新页面操作 | 当openRefresh为true时必传 | 无 |
refreshTokenStore(refreshToken) | Function | refreshToken为当前浏览器缓存的refreshToken,需要返回一个Promise,利用此refreshToken调用接口获取新的accessToken 并设置。 | 当openRefresh为true时必传 | 无 |
setAccessTokenFun(config, accessToken) | Function | config为该请求的config,accessToken 为新获取的accessToken, 此处需要将accessToken设置到请求头中 | 当openRefresh为true时必传 | 无 |
responseResultFun(res) | Function | res为axios实例返回的res,格式化接口请求成功后返回的数据 | 非必传 | axios实例返回的res |
formatAccessTokenFun(data) | Function | data为responseResultFun报错时返回的res | 非必传 | axios实例返回的res.data.accessToken |
accessTokenExpirationCode | number | 配置accessToken过期返回的业务状态码 | 非必传 | 401 |
refreshTokenExpirationCode | number | 配置refreshToken过期返回的业务状态码 | 非必传 | 403 |