axios取消请求总结(转)
书到用时方恨少,事非经过不知难。(陆游)
·
书到用时方恨少,事非经过不知难。(陆游)
应用场景
取消请求在前端有时候会用到,以下是两个工作中可能会用到的场景
- tab切换时刷新某个列表数据,如果他们共用一个变量存储数据列表,当请求有延时,可能会导致两个tab数据错乱;
- 导出文件或下载文件时,中途取消 。
如何取消请求
给构造函数 CancelToken 传递一个 executor 函数作为参数。这种方法的好处是,可以用同一个 cancel token 来取消多个请求
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// 参数 c 也是个函数
cancel = c;
})
});
// 取消请求,参数用法同上
cancel();
项目中用法示
日常项目会对axios 做二次封装。token传递,请求拦截,响应拦截。参数封装
import axios from 'axios';
import {ElMessage} from 'element-plus';
import {removeToken, getToken} from '/@/utils/storage';
import {toQueryString, isObject} from '/@/utils/util';
// 配置新建一个 axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API as any,
timeout: 50000,
headers: {'Content-Type': 'application/json'},
});
// 添加请求拦截器
service.interceptors.request.use(
(config) => {=
// 在发送请求之前做些什么 token
if (getToken()) {
if (config.headers) {
config.headers.Authorization = `Bearer ${getToken()}`;
} else {
config.headers = {
Authorization: `Bearer ${getToken()}`
}
}
}
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
const finalReturn = (response: any) => response.config.fullResponse ? response : response.data
// 添加响应拦截器
service.interceptors.response.use(
async (response) => {
// 对响应数据做点什么
const res = response.data;
const state = Number(res.state) || 200
if (state === 1000) {
return finalReturn(response)
} else if (state === 700 || state === 2000) {
removeToken()
window.location.reload()
} else {
ElMessage({
message: res.message || res.msg || 'Error',
type: 'error',
duration: 5 * 1000
})
const error = {
'错误URL': response.config.url,
'状态码': response.request.status,
'返回数据': response.request.response
}
return new Error(JSON.stringify(error, null, '\t'))
}
return res;
},
(error) => {
ElMessage({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
);
对于某一个请求添加取消的功能,要在调用api时,加上cancelToken选项,使用时的示例:
// api.js
import request from 'request'
export function getUsers(page, options) {
return request({
url: 'api/users',
params: {
page
},
...options
})
}
// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: null
...
toCancel() {
this.cancel('取消请求')
}
getUsers(1,
{
cancelToken: new CancelToken(c => (this.cancel = c))
}
)
.then(...)
.catch(err => {
if (isCancel) {
console.log(err.message)
} else {
...
}
})
以上,我们就可以顺顺利利地使用封装过的axios,取消某一个请求了。其原理无非就是把cancelToken的配置项,在调用api时加上,然后就可以在业务代码取消特定请求了。
用数组保存每个需要取消的cancel token,然后逐一调用数组里的每一项即可
// User.vue
import { CancelToken, isCancel } from 'axios'
import { getUsers } from 'api'
...
cancel: []
...
toCancel() {
while (this.cancel.length > 0) {
this.cancel.pop()('取消请求')
}
}
getUser1(1,
{
cancelToken: new CancelToken(c1 => (this.cancel.push(c1)))
}
)
getUser2(2,
{
cancelTokem: new CancleTokem(c2 => (this.cancel.push(c2)))
}
)
切换路由时,取消请求
大概思路就是在请求拦截器里,统一加个token,并设置全局变量source控制一个cancel token,在路由变化时调用cancel方法。
http.interceptors.request.use(config => {
config.cancelToken = store.source.token
return config
}, err => {
return Promise.reject(err)
})
router.beforeEach((to, from, next) => {
const CancelToken = axios.CancelToken
store.source.cancel && store.source.cancel()
store.source = CancelToken.source()
next()
})
// 全局变量
store = {
source: {
token: null,
cancel: null
}
}
axios 从 v0.22.0 开始,支持以 fetch API 方式—— AbortController 取消请求
主要代码:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
// request.js
// 添加请求拦截器
service.interceptors.request.use(
(config) => {
// 创建AbortController 实例
const controller = new AbortController();
useRoutesListStore().setController(controller)
// config.headers.common['Authorization'] = `Bearer dfb1ed07-3318-4549-b18b-9791161ef62b`
// 在发送请求之前做些什么 token
if (getToken()) {
if (config.headers) {
config.headers.Authorization = `Bearer ${getToken()}`;
} else {
config.headers = {
Authorization: `Bearer ${getToken()}`
}
}
// config.headers.common['Authorization'] = `Bearer ${Session.get('token')}`
}
// config中配置signal
config.signal = controller.signal
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
需要的页面在onMounted中引用下
// index.vue
onUnmounted(() => {
// 取消上一个路由的请求
const routeListStore = useRoutesListStore()
routeListStore.$state.requestController?.abort()
})
更多推荐
已为社区贡献2条内容
所有评论(0)