vue-axios-optimize,轻松实现取消前面重复请求或禁用后面的重复请求及无感知刷新accessToken

优势

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中的axiosimport 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,此处可执行关闭全局动画的操作
openRefreshBoolean是否开启无感知刷新tokenfalse
refreshApiUrlString请求刷新token接口的api地址 如/xiaobu-admin/refresh-token当openRefresh为true时必传
getRefreshTokenFun()Function获取当前项目的 refreshToken方法, 记得 return 回去当openRefresh为true时必传
reloginFun(response)Functionresponse 为axios实例中返回的数据,此处建议执行清除token相关缓存并弹框提示,点击确认进行刷新页面操作当openRefresh为true时必传
refreshTokenStore(refreshToken)FunctionrefreshToken为当前浏览器缓存的refreshToken,需要返回一个Promise,利用此refreshToken调用接口获取新的accessToken 并设置。当openRefresh为true时必传
setAccessTokenFun(config, accessToken)Functionconfig为该请求的config,accessToken 为新获取的accessToken, 此处需要将accessToken设置到请求头中当openRefresh为true时必传
responseResultFun(res)Functionres为axios实例返回的res,格式化接口请求成功后返回的数据非必传axios实例返回的res
formatAccessTokenFun(data)Functiondata为responseResultFun报错时返回的res非必传axios实例返回的res.data.accessToken
accessTokenExpirationCodenumber配置accessToken过期返回的业务状态码非必传401
refreshTokenExpirationCodenumber配置refreshToken过期返回的业务状态码非必传403

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值