2023 - 04 -07 更新
在v0.22.0版本後官方棄用了CancelToken的方法,並改支援AbortController在使用AbortController一定要記得檢查自己的版本號
換成AbortController整體概念與CancelToken相同
window._axiosPromiseArr = [] // 全局聲明 (變數掛在window下)
// http request 拦截器
axios.interceptors.request.use(
config => {
config.headers = {
'Content-Type': 'application/json;charset=UTF-8'
};
// 每个请求都会 加入
const controller = new AbortController()
config.signal = controller.signal
window._axiosPromiseArr.push(controller)
return config
},
路由跳前
router.beforeEach((to, from, next) => {
window._axiosPromiseArr.forEach((el, index) => {
el.abort() // 路由跳转之前,中止请求
// 重置 window._axiosPromiseArr
delete window._axiosPromiseArr[index]
})
next();
})
目前還有遇到過一個需求是如果有重複呼叫api行為時,取消上一個呼叫
主要的問題是如何判斷此api為同一個api
整體的思路是使用Symbol() (存在requestId)來為api創建id, 呼叫api前利用這個id推到new Map當中,
如果回傳成功以後再從new Map裡使用id找到對應的function將其刪除
目前有方法但是待優化,因為變成每個需要判斷的api都要新增一個Symbol()…
const requestIdMap = new Map()
service.interceptors.request.use(
function (config) {
/*--以上省略--*/
if (!config.requestId) return config
let controller = requestIdMap.get(config.requestId)
if (controller) {
controller.abort()
requestIdMap.delete(config.requestId)
}
controller = new AbortController()
requestIdMap.set(config.requestId, controller)
config.signal = controller.signal
return config
},
function (error) {
return Promise.reject(error)
}
)
// 響應攔截器
service.interceptors.response.use(
function (response) {
if (response.config.signal) requestIdMap.delete(response.config.signal)
return response.data
},
async function errorHandler(error) {
if (error.message !== 'canceled') {
requestIdMap.delete(error.signal)
}
return Promise.reject(error)
}
)
在網路上看過很多版本的用法,理念都是相同的都是使用axios中的CancelToken方法
在攔截器裡面統一在每次發送請求時,將請求加入至要取消地arry中
這個arry網上有其他作法是使用vuex來調用,但是對於我的項目來說vuex管理數據已經太龐大,後來又看到更簡單的做法是直接把arry掛在window下
window._axiosPromiseArr = [] // 全局聲明 (變數掛在window下)
// http request 拦截器
axios.interceptors.request.use(
config => {
config.headers = {
'Content-Type': 'application/json;charset=UTF-8'
};
// 每个请求都会 加入
config.cancelToken = new axios.CancelToken(cancel => {
// 这个我习惯放再window 里面,也有配置再vuex里面的 感觉太麻烦了
window._axiosPromiseArr.push({ cancel })
})
return config
},
在main.js中調用全局的router.beforeEach
router.beforeEach((to, from, next) => {
window._axiosPromiseArr.forEach((el, index) => {
el.cancel() // 路由跳转之前,中止请求
// 重置 window._axiosPromiseArr
delete window._axiosPromiseArr[index]
})
next();
})
如果說有些請求是用來初始化或是其他業務需求而不能取消請求的,那麼只要加個判斷條件即可
axios.interceptors.request.use(
config => {
config.headers = {
'Content-Type': 'application/json;charset=UTF-8'
};
// 每个请求都会 加入
if (config.headers.cancelRequest !== false){
config.cancelToken = new axios.CancelToken(cancel => {
// 这个我习惯放再window 里面,也有配置再vuex里面的 感觉太麻烦了
window._axiosPromiseArr.push({ cancel })
})
}
return config
},
在API管理的地方加入條件就大功告成啦
axios.post('/user', null, {
headers: {
cancelRequest: false
}
});
轉載至 : vue 路由切换时 中止未完成的请求 BY aInkFish