Appearance
快速开始
阅读此处时,默认您已经完全熟悉axios请求优化包的相关配置,如还未完全了解,请阅读使用须知。
安装
shell
npm i vue-axios-optimize -S建议api接口请求目录如下
src
api
modules
common-api.js
system-api.js
index.js
axios.js
axios-optimize.js
axios.js 为axios相关配置,基础请求路径、请求超时时间、请求拦截与响应拦截的配置文件。
axios-optimize.js 为axios请求优化包配置文件,后续请求方法均需引入此文件。
common-api.js、system-api.js 为通用接口请求方法,如获取用户信息、获取权限信息、获取菜单信息等。
index.js 为api接口请求方法入口文件,引入common-api.js、system-api.js,并导出。
axios.js 配置
请求拦截处需注意的地方:
js
service.interceptors.request.use(
(config) => {
// ... 一系列请求前操作
return config
},
(error) => {
// 此处一定要写成这样, 尤其是return 一定要有
return Promise.reject(error)
}
)响应拦截处需注意的地方:
js
// 对于错误的响应需要
return { ...data, config, responseErr: true }
// 对于正确的响应需要
return { ...data, config, responseErr: true }下列是vue2-element-admin后台管理系统框架对于响应拦截的相关配置,实现了下载文件名跟随后端配置,详细可阅读前端处理Blob文件下载:实现动态文件名跟随后端配置,实现了权限变更时的弹框提示,同时也解决了当返回类型为文件流且AccessToken过期时的续签配置。以vue2-element-admin为例,对后端的要求就是当请求文件流响应格式的接口报错时,将status-code设置成520,且手动设置一个响应头,其值为401或者403时将错误信息return给vue2-axios-optimize处理。
响应拦截示例:
js
// 具体方法请阅读 前端处理Blob文件下载:实现动态文件名跟随后端配置
import { getFilenameFromContentDisposition } from "@/utils/file"
service.interceptors.response.use(
async(response) => {
const { data, config, status, request } = response
// 如果自定义代码不是200,则判断为错误。
if (status !== 200) {
modal.msgError(data.message || "Error")
return { ...data, config, responseErr: true }
} else {
// 二进制数据则直接返回
if (
request.responseType === "blob" ||
request.responseType === "arraybuffer"
) {
// 获取 Content-Disposition 头
const contentDisposition = response.headers["content-disposition"]
// 解析文件名
const fileName = getFilenameFromContentDisposition(contentDisposition) // 默认文件名 为空
if (fileName) {
// 存储文件名 用于设置和后端一样的文件名
localStorage.setItem("downloadFileName", fileName)
}
return response
}
if (data.code === 200) {
return { ...data, config }
}
if (data.code === 401 || data.code === 403) {
return { ...data, config, responseErr: true }
}
// 用户权限变更
if (data.code === 402) {
if (isShowingModal) {
return { ...data, config, responseErr: true }
}
isShowingModal = true
modal
.confirm(data.message, {
type: "warning",
showClose: false
})
.then(async() => {
// 刷新去首页吧
window.location.href =
window.location.origin + window.location.pathname
})
.catch(async(err) => {
// 关闭 MessageBox 后,手动移除 不能关闭的遮罩层
const maskModal = document.querySelector(".v-modal")
if (maskModal) {
maskModal.remove()
}
await store.dispatch("user/getUserInfo")
isShowingModal = false
})
return { ...data, config, responseErr: true }
}
modal.msgError(data.message || "Error")
return { ...data, config, responseErr: true }
}
},
(error) => {
// 加入try 否则 会导致 取消重复请求时 因为无config等字段导致报错 导致取消重复请求失效
try {
const { config, headers, status } = error.response
if (status === 520) {
// 导出文件接口报错时与后端约定 返回状态码为 520
// 约定好响应头添加 x-custom-header 且值为原本报错的 code
const code = Number(headers["x-custom-header"])
console.log("🚀 ~ code:", code)
// 当code为401 或者 403时 触发刷新token接口或者弹框提示过期重新登录
if (code === 401 || code === 403) {
return {
code,
message: "凭证已过期,请重新登录!",
config,
responseErr: true
}
} else {
modal.msgError(code === 409 ? "无权限" : error.message || "Error")
return Promise.reject(error)
}
}
} catch (err) {
console.log("🚀 ~ err:", err)
}
if (error.name !== "CanceledError") { // 非取消请求时 才提示错误
// 如果是请求超时
if (error.code === "ECONNABORTED") {
// 当 不是重发请求或者不是最后一次重发导致的报错时 提示 超时重发版本需要加这个判断
if (!(error?.config?.currentRetryTimes && error?.config?.maxRetryTimes && error.config.currentRetryTimes < error.config.maxRetryTimes)) {
modal.msgError(error.message || "Error")
}
} else {
modal.msgError(error.message || "Error")
}
}
return Promise.reject(error)
}
)上述响应拦截配置是相对完整的配置,对于无配置无感续签凭证的配置会相对少很多,切记一个原则就是:
js
const { data, config, status, request } = response
// 对于错误的响应需要
return { ...data, config, responseErr: true }
// 对于正确的响应需要 responseErr 可配置为 false 或者不用配置此字段
return { ...data, config, responseErr: false }温馨提示
您原先请求拦截处的 error 错误处理一定要加个 return Promise.reject(error),return 关键字很重要 您原先响应拦截处对于需要报错提示的地方,需返回错误信息给优化包:return { ...data, config, responseErr: true } 您原先响应拦截处对于正确的响应,尾部需返回正确数据给优化包:return { ...data, config, responseErr: false } 接口异常响应拦截时,对于取消请求的场景不给予错误消息提示
const { data, config, status, request } = response
axios-optimize.js 配置项
重磅来袭,包的配置来了,直接引入配置代码示例吧
js
import axios from "axios"
import instance from "@/api/axios"
import axiosOptimize from "vue-axios-optimize"
import store from "@/store"
import {MessageBox} from "element-ui"
let isAlertShowing = false // 是否弹出messaBox.alert
// https://www.npmjs.com/package/vue-axios-optimize
const AxiosOptimize = new axiosOptimize(axios, instance, {
maxReqNum: 2, // 同时最多请求数量 选配 默认 6
cacheNum: 2, // 缓存数量 选配 默认10
responseTypesStr: "arraybuffer,blob", // 当axios请求设置 responseType为arraybuffer或blob时,直接返回原始数据 选配
showLoadingFun: (config, requestingNum) => { // 当需要加载动画的请求数量不为0时的回调函数
store.commit("app/SET_LOADING_STATUS", true)
},
hideLoadingFun: (config, requestingNum) => { // 当需要加载动画的请求数量为0时的回调函数
store.commit("app/SET_LOADING_STATUS", false)
},
responseResultFun: (res) => { // 响应数据格式化
return res.data
},
openRefresh: true, // 是否开启无感知刷新token 以下配置均与无感知刷新token有关 如无需配置无感知刷新token 可忽略
code: "code", // 判断响应码的字段标识 默认code
authorizationKey: "Authorization", // headers存放凭证的字段名
accessTokenExpirationCode: 401, // accessToken过期时 接口响应状态码 默认 数字类型 401
refreshTokenExpirationCode: 403, // 刷新token接口请求报错时的 响应状态码 默认 数字类型 403
setAuthorizationFun: (config, authorization) => { // 设置接口请求token的 并返回新的config 默认为 config.headers.Authorization = "Bearer " + accessToken
config.headers.Authorization = authorization
return config
},
getRefreshTokenFun: () => { // 获取refreshToken的方法
return store.getters.refreshToken
},
getAuthorizationFun: () => { // 获取Authorization的方法
return "Bearer " + store.getters.accessToken
},
refreshTokenStore: (refreshToken) => { // 调用刷新token的方法 并将获取到的数据存储到cookie 且需要将接口返回的数据 resolve(data)
return store.dispatch("user/refreshToken", refreshToken)
},
reloginFun: async(response) => { // 刷新token接口也报错后的处理逻辑 建议进行类似如下方法处理
if (isAlertShowing) {
return
}
isAlertShowing = true
// 重新登录方法 弹框提示 点击确认后 建议清除 缓存中token等信息后 刷新页面
MessageBox.alert(`${response.message}`, "提示", {
confirmButtonText: "OK",
showClose: false,
callback: async(action) => {
isAlertShowing = false
if (action === "confirm") {
// 清除缓存中的token等信息
store.commit("user/CLEAR_AUTH")
// 刷新浏览器是为了 跳转登录页时query的redirect 会带上 当前页面地址(路由拦截处的逻辑)
window.location.reload()
}
}
})
}
})
export default AxiosOptimize普通请求接口处配置
接口处直接引入五种常用请求方式的使用示例吧:
js
import axiosRequest from '@/api/axios-optimize';
// 需要配置 请求接口时 不加载全局动画 则 配置 noShowLoading: true
// 需要配置 缓存的接口 则 配置 cache: true 否则 配置为 false 或 不配置
// 需要配置 重复请求时 取消前面的请求 则 配置 preventDuplicateRequestsType: "cancel"
// 需要配置 重复请求时 禁用后面的请求 则 配置 preventDuplicateRequestsType: "prevent"
// 需要配置 返回数据是否添加 IS_COMPLETE 是否完成字段 则 配置 showIsComplete: true
// 需要配置 当同时请求很多接口,且还有很多接口在队列时,有接口报错,是否终止所有队列中的接口请求 removeRemainingTasksWhenError: true
// 需要配置 全路经(包括入参数据)为接口唯一标识的 则配置 fullPath: true 否则 配置为 false 或 不配置 否则仅仅以URL为唯一标识
// 续签AccessToken接口需要配置isRefreshToken为true
// get 请求demo
export function getDemo(
data = {},
config = {
noShowLoading: true, // 配置不展示加载动画
preventDuplicateRequestsType: 'cancel', // 配置重复请求时 取消前面的请求
},
) {
return axiosRequest.get(`/xiaobu/getDemo`, { params: data, ...config });
}
// post 请求demo
export function postDemo(data = {}, config = {}) {
return axiosRequest.post(`/xiaobu/postDemo`, data, config);
}
// delete 请求demo1 使用data作为参数 参数不展示在 请求路径上
export function deleteDemo1(data = {}, config = {}) {
return axiosRequest.delete(`/xiaobu/deleteDemo1`, { data, ...config });
}
// delete 请求demo2 使用params作为参数 参数展示在 请求路径上
export function deleteDemo2(data = {}, config = {}) {
return axiosRequest.delete(`/xiaobu/deleteDemo2`, {
params: data,
...config,
});
}
// put 请求demo
export function putDemo(data = {}, config = {}) {
return axiosRequest.put(`/xiaobu/putDemo`, data, config);
}
// patch 请求demo
export function patchDemo(data = {}, config = {}) {
return axiosRequest.patch(`/xiaobu/patchDemo`, data, config);
}使用时 直接就是
js
getDemo().then()可中断的接口处配置
可中断的接口配置与普通接口的配置项完全一致,仅在使用时不一样,规则如下:
js
import axiosRequest from '@/api/axios-optimize';
import { createCancelableRequest } from 'vue-axios-optimize/utils.js';
export function getDemo(
data = {},
config = {
noShowLoading: true, // 配置不展示加载动画
preventDuplicateRequestsType: 'cancel', // 配置重复请求时 取消前面的请求
},
) {
return createCancelableRequest(axiosRequest, 'get', `/xiaobu/getDemo`, { params: data, ...config });
}
// post 请求demo
export function postDemo(data = {}, config = {}) {
return createCancelableRequest(axiosRequest, 'post', `/xiaobu/postDemo`, data, config);
}
// delete 请求demo1 使用data作为参数 参数不展示在 请求路径上
export function deleteDemo1(data = {}, config = {}) {
return createCancelableRequest(axiosRequest, 'delete', `/xiaobu/deleteDemo1`, { data, ...config });
}
// delete 请求demo2 使用params作为参数 参数展示在 请求路径上
export function deleteDemo2(data = {}, config = {}) {
return createCancelableRequest(axiosRequest, 'delete', `/xiaobu/deleteDemo2`, {
params: data,
...config,
});
}
// put 请求demo
export function putDemo(data = {}, config = {}) {
return createCancelableRequest(axiosRequest, 'put', `/xiaobu/putDemo`, data, config);
}
// patch 请求demo
export function patchDemo(data = {}, config = {}) {
return createCancelableRequest(axiosRequest, 'patch', `/xiaobu/patchDemo`, data, config);
}使用时
js
const { cancel, request } = getDemo()
request.then(res => {})
cancel()超时重发的接口处配置
超时重发接口处配置继承普通接口配置的所有配置项,并且多了widthCancel配置项, 具体如下
js
import axiosRequest from '@/api/axios-optimize';
import { requestWithRetry } from 'vue-axios-optimize/utils.js';
export function getDemo(
data = {},
config = {
noShowLoading: true, // 配置不展示加载动画
preventDuplicateRequestsType: 'cancel', // 配置重复请求时 取消前面的请求
timeout: 5000, // 配置请求超时时间 requestWithRetry 方法时 默认为 10000
widthCancel: true, // 配置是否可主动取消请求 为true时 使用方法不一样 得注意
},
) {
return requestWithRetry(axiosRequest, 'get', `/xiaobu/getDemo`, { params: data, ...config });
}
// post 请求demo
export function postDemo(data = {}, config = {}) {
return requestWithRetry(axiosRequest, 'post', `/xiaobu/postDemo`, data, config);
}
// delete 请求demo1 使用data作为参数 参数不展示在 请求路径上
export function deleteDemo1(data = {}, config = {}) {
return requestWithRetry(axiosRequest, 'delete', `/xiaobu/deleteDemo1`, { data, ...config });
}
// delete 请求demo2 使用params作为参数 参数展示在 请求路径上
export function deleteDemo2(data = {}, config = {}) {
return requestWithRetry(axiosRequest, 'delete', `/xiaobu/deleteDemo2`, {
params: data,
...config,
});
}
// put 请求demo
export function putDemo(data = {}, config = {}) {
return requestWithRetry(axiosRequest, 'put', `/xiaobu/putDemo`, data, config);
}
// patch 请求demo
export function patchDemo(data = {}, config = {}) {
return requestWithRetry(axiosRequest, 'patch', `/xiaobu/patchDemo`, data, config);
}未配置 widthCancel或者配置值为 false 时,使用如下
js
getDemo().then(res => {})配置 widthCancel值为 true 时,使用如下
js
const { cancel, request } = getDemo()
request.then(res => {})
cancel()总结
经过上述一系列处理后,我们的配置就完成啦,更多细节及注意事项请继续阅读文档。

