实现功能:
- 取消掉重复的请求
- 路由跳转可以取消上个页面没发送的请求
- 统一请求方式 post get put delect格式统一
- 封装上传下载
- 统一提示实现(提供配置自定义提示)
- 非200状态码 错误信息只提示一次
- 大文件分片上传的封装,某一片上传失败 自动上传2次
用法
import { axios } from '@/common/request/index'
axios.post('/proxyapi/api/sys/auth/login', data, { headers: { Authorization: ''}, noMessage: true })
axios.get('/proxyapi/api/sys/auth/login-user', data, { headers: { Authorization: ''} })
axios.requestFormData('url', {file:file},{chuckSize:300})
axios.requestExcelStream('url', {})
代码封装
import axios from 'axios'
import qs from 'qs'
import { router } from "@/router/index";
import { message } from "ant-design-vue";
import { store } from '@/store/index'
class request {
http = {}
pending = new Map()
errorStatus = {
'400': (Message = '系统错误') => { message.error(Message); },
'401': (Message = '登录过期', router) => {
message.error(Message);
const timeout = setTimeout(() => {
clearTimeout(timeout);
store.commit({ type: 'logOut/logOut' })
router.replace({ name: "login" });
}, 500);
},
'403': (Message = '没有权限') => {
message.error(Message)
const timeout = setTimeout(() => {
clearTimeout(timeout);
router.replace({ path: "/error", query: { title: '没有权限', status: 403 } });
}, 500);
},
'404': (Message = '地址错误') => { message.error(Message) },
'500': (Message = '系统错误') => { message.error(Message) },
'504': (Message = '网关超时') => { message.error(Message) },
}
constructor(baseURL = '', timeout = 10000, token, header = 'application/json;charset=UTF-8') {
if (!request.instance) {
request.instance = this
this.pending = new Map();
this.init(baseURL, timeout, token, header)
}
return request.instance
}
dealUrl(config = {}, type = 'request') {
const method = config.method.toLocaleLowerCase(),
url = config.url
if (type === 'request') {
if (['get', 'delect'].includes(method)) return `${url}?params=${JSON.stringify(config?.params)}?method=${method}`
if (['post', 'put'].includes(method)) return `${url}?data=${JSON.stringify(config?.data)}?method=${method}`
return ''
}
if (['get', 'delect'].includes(method)) return `${url}?params=${JSON.stringify(config?.params)}?method=${method}`
if (['post', 'put'].includes(method)) return `${url}?data=${JSON.stringify(JSON.parse(config?.data))}?method=${method}`
return ''
}
addPending(config = {}) {
config.cancelToken = new axios.CancelToken(cancle => {
const url = this.dealUrl(config, 'request')
this.pending.set(url, cancle)
})
}
canclePending(config = {}, type = 'request') {
const url = this.dealUrl(config, type)
if (!this.pending.has(url)) return
this.pending.get(url)?.()
this.pending.delete(url)
}
init(baseURL, timeout, token, header) {
this.http = axios.create({
baseURL,
timeout,
headers: {
'Content-type': header,
Authorization: token,
}
});
this.request()
this.response()
}
request() {
this.http.interceptors.request.use(config => {
debugger
if (!config.headers.Authorization) {
config.headers.Authorization = store.getters['user/getToken'] ?? ''
}
if (config?.ifAddPending) {
this.canclePending(config)
this.addPending(config)
}
const params = config?.data ?? {}
for (let key in params) {
if (params[key] && typeof params[key] === 'string') params[key] = params[key]?.trim()
}
if (config?.headers?.['Content-type'] === 'application/x-www-form-urlencoded') {
config.data = qs.stringify(config.data)
}
return config
}, error => {
return Promise.reject(error);
});
}
response() {
this.http.interceptors.response.use(response => {
const { statusText, data, config } = response
if (config?.ifAddPending) {
this.canclePending(config, 'response')
}
if (statusText === "OK") {
if (!config?.noMessage) {
if (!data?.Success) message.error(data?.Message)
if (data?.Success) message.success(data?.Message)
}
return data
}
return {}
}, error => {
for (let cb of this.pending.values()) {
cb?.()
}
this.pending?.clear()
if (error?.code === 'ERR_CANCELED') return
if (!error?.response) return message.error('服务器断开连接');
const {
data: { Success = true, Code, Message },
status
} = error?.response;
if (!error?.config?.noMessage) this.errorStatus?.[status + '']?.(Message, router)
return Promise.reject(error?.response ?? {});
});
}
}
export default request
import request from "./axios";
import { message } from "ant-design-vue";
import { store } from '@/store/index'
let instance = new request('', 5000, store.getters['user/getToken'], 'application/json;charset=UTF-8')
export class axios {
static pending() {
return instance.pending;
}
static async commonFnData(url = '', data, config = {}, method) {
if (!url || config?.constructor?.name !== 'Object') {
message.error("请输入正确参数");
return Promise.reject({ Success: false })
}
try {
const res = await instance.http({
url,
method,
data,
...config
})
if (res?.Success) return Promise.resolve(res)
return Promise.reject({ Success: false, error: res })
} catch (error) {
return Promise.reject({ Success: false, error })
}
}
static async commonFnParams(url = '', params, config = {}, method) {
if (!url || config?.constructor?.name !== 'Object') {
message.error("请输入正确参数");
return Promise.reject({ Success: false })
}
try {
const res = await instance.http({
url,
method,
params,
...config
})
if (res?.Success) return Promise.resolve(res)
return Promise.reject({ Success: false, error: res })
} catch (error) {
return Promise.reject({ Success: false, error })
}
}
static async post(url, data, config) {
return axios.commonFnData(url, data, config, 'post')
}
static async put(url, data, config) {
return axios.commonFnData(url, data, config, 'put')
}
static async get(url, params, config) {
return axios.commonFnParams(url, params, config, 'get')
}
static async delect(url, params, config) {
return axios.commonFnParams(url, params, config, 'delect')
}
static async requestFormData(url, data, config = {}, method = 'post') {
const { name, size } = data?.file,
{ file } = data,
{ chuckSize } = config,
params = { ...data }
if (!chuckSize || chuckSize > size) {
const formData = new FormData()
for (let key in params) {
formData.append(key, params[key])
}
return axios.commonFnData(url, formData, { ...config, headers: { 'Content-type': 'multipart/form-data' } }, method)
}
const chuckLen = Math.ceil(size / chuckSize)
const uploadArr = Array.from({ length: chuckLen }).map((item, index) => {
const result = file.slice(index * chuckSize, (index + 1) * chuckSize),
blob = new Blob([result], { type: file?.type }),
formData = new FormData()
blob.name = file.name
params.index = index
for (let key in params) {
if (key === 'file') formData.append('file', blob)
else formData.append(key, params[key])
}
return () => axios.commonFnData(url, formData, { ...config, headers: { 'Content-type': 'multipart/form-data' } }, method)
})
const res = await Promise.allSettled(uploadArr?.map(item => item()))
res?.map((item, index) => {
if (item?.status === 'rejected') {
uploadArr[index]().catch(() => {
uploadArr[index]().then(() => {
res[index].status = 'fulfilled'
})
})
}
})
return res
}
static async requestExcelStream(url = '', params = {}, config = {}, method = 'get') {
const res = await axios.commonFnParams(url, params, { responseType: 'blob', ...config }, method)
if (res.status === 200) {
var blob = res.data
var reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = function (e) {
var a = document.createElement('a')
a.download = (params && params.getStreamPage || '表格') + Date.now()
a.href = e.target.result
a.click()
a.remove();
}
}
}
}