網站首頁 編程語言 正文
實現功能:
- 取消掉重復的請求
- 路由跳轉可以取消上個頁面沒發送的請求
- 統一請求方式 post get put delect格式統一
- 封裝上傳下載
- 統一提示實現(提供配置自定義提示)
- 非200狀態碼 錯誤信息只提示一次
- 大文件分片上傳的封裝,某一片上傳失敗 自動上傳2次
用法
import { axios } from '@/common/request/index'
// noMessage 是否提示
axios.post('/proxyapi/api/sys/auth/login', data, { headers: { Authorization: ''}, noMessage: true })
axios.get('/proxyapi/api/sys/auth/login-user', data, { headers: { Authorization: ''} })
// 上傳 不需要加請求頭配置已經自己加了 不需要formData 配置自己加了
// chuckSize有的話就是分片上傳 沒有的話就是普通一次上傳
// chuckSize值的單位是字節(一次上傳多大)
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
}
// 處理pending的url
dealUrl(config = {}, type = 'request') {
const method = config.method.toLocaleLowerCase(),
url = config.url
// 請求的config拼裝(pending的key)
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 ''
}
// 響應的config拼裝(pending的key)
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 ''
}
// 添加peding
addPending(config = {}) {
config.cancelToken = new axios.CancelToken(cancle => {
const url = this.dealUrl(config, 'request')
this.pending.set(url, cancle)
})
}
// 取消pending
canclePending(config = {}, type = 'request') {
const url = this.dealUrl(config, type)
// 去尋找pending里是否有和本次相同的請求 有的話就取消上一次請求 并且刪除pending的重復記錄
if (!this.pending.has(url)) return
// 取消上次請求
this.pending.get(url)?.()
// 刪除上次記錄
this.pending.delete(url)
}
init(baseURL, timeout, token, header) {
// 創建一個axios實例
this.http = axios.create({
baseURL,
timeout,
headers: {
'Content-type': header,
Authorization: token, // 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)
// 添加pending
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)
}
// // formData格式
// if (config?.headers?.['Content-type'] === 'multipart/form-data') {
// const params = { ...config.data }
// const formData = new FormData()
// for (let key in params) {
// formData.append(key, params[key])
// }
// config.data = formData
// }
return config
}, error => {
return Promise.reject(error);
});
}
// 添加響應攔截器
response() {
this.http.interceptors.response.use(response => {
const { statusText, data, config } = response
if (config?.ifAddPending) {
// 取消pending
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 => {
// 取消pending
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'
// import { watch } from 'vue'
let instance = new request('', 5000, store.getters['user/getToken'], 'application/json;charset=UTF-8')
// watch(() => store.getters['user/getToken'], (token) => {
// instance = new request('', 5000, token, 'application/json;charset=UTF-8')
// })
export class axios {
// 暴露出去方便 1. 切換導航時取消掉未結束的請求 2. 添加全局loading防止請求未完成時切換導航 (任選一種)
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) {
// formData格式
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()))
// 上傳失敗 重復上傳2次
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) // 轉換為base64,可以直接放入a表情href
reader.onload = function (e) {
// 轉換完成,創建一個a標簽用于下載
var a = document.createElement('a')
a.download = (params && params.getStreamPage || '表格') + Date.now()
a.href = e.target.result
a.click()
a.remove();
}
}
}
}
原文鏈接:https://blog.csdn.net/weixin_44147791/article/details/125043938
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-10-16 Android基于方法池與回調實現登錄攔截的場景_Android
- 2022-06-16 golang?validator庫參數校驗實用技巧干貨_Golang
- 2023-06-04 pycharm中下載的包但是import還是無法使用/報紅的解決方法_python
- 2021-12-02 C語言中幾種常量的認識和理解_C 語言
- 2022-02-27 Postgres -- 報錯:right sibling‘s left-link doesn‘t m
- 2022-10-02 Linux?Shell?自動交互功能實現_linux shell
- 2023-01-05 TensorFlow?2.0之后動態分配顯存方式_python
- 2022-08-06 Golang并發讀取文件數據并寫入數據庫的項目實踐_Golang
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支