之前使用axios都是调用普通的请求,但是直到项目中遇到了一些稍微复杂的交互,比如输入框搜索需要取消上一次的重复请求,所以结合之前的经验,再封装一次带有取消请求axios方法。(可跳到最后看全部代码)
1. axios的取消事件
方法一:可以使用 CancelToken.source 工厂方法创建 cancel token
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
方法二: 通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// cancel the request
cancel();
单独使用axios的时候,两个方法都可以,但是封装好axios方法在vue中全局调用时,方法一有个问题,axios的cancel方法会把即将要发出的请求取消掉,所以用第二个方法
2. 封装取消方法
import axios from 'axios'
// 基本配置
let baseUrl = 'http://127.0.0.1:3000'
let timeout = 60000
Object.assign(axios.defaults, {
baseURL: baseUrl,
timeout,
headers: { 'Content-Type': 'application/json;charset=UTF-8'}
})
// object对象存放每次new CancelToken生成的方法
let source = {}
// 每次请求前都会把api放在此数组中,响应成功后清除此请求api
let requestList = []
// 请求拦截器
axios.interceptors.request.use(config => {
// do something
// 查询状态提示...
// 对请求参数做处理
return config
}, function (error) {
return Promise.reject(error)
})
// 响应拦截器
axios.interceptors.response.use(response => {
// do something
// 关闭查询状态
// 获取请求的api
const request = JSON.stringify(response.config.url)
// 请求完成后,将此请求从请求列表中移除
requestList.splice(requestList.findIndex(el => el === request), 1)
return response
}, function (err) {
// 报错信息没法获取config
if (axios.isCancel(err)) {
// 根据业务场景确定是否需要清空
// 例如:页面跳转前,清空离开页面的请求
requestList.length = 0
} else {
console.log(err)
}
return Promise.reject(err)
})
// 定义取消方法
/**
*
* @param {*} api
* @param {Boolean} allCancel
*/
function cancelRequest(api, allCancel){
// 请求列表里存在此api,即发起重复请求,把之前的请求取消掉
if (api && requestList.includes(api) && typeof source[api] ==='function'){
source[api]('终止请求')
} else if (!api && allCancel) {
// allCancel为true则请求列表里的请求全部取消
requestList.forEach(el => {
source[el]('批量终止请求')
})
}
}
function request(method, api, params = {}, options = {}) {
// 取消上一次请求
if (requestList.length) cancelRequest(api)
return new Promise((resolve, reject) => {
if (method === 'get') {
options.params = params
} else {
options.data = params
}
const config = Object.assign(
{
url: api,
method,
// source对象保存取消方法
cancelToken: new axios.CancelToken(function executor(c) {
source[api] = c;
})
},
options
)
// 请求前将api推入requestList
requestList.push(api)
axios.request(config)
.then(res => {
resolve(res)
})
.catch(err => {
console.log(err)
reject(err)
})
})
}
// 把cancelRequest方法暴露出去
const http = {
// bind偏函数预设参数
get: request.bind(null, 'get'),
post: request.bind(null, 'post'),
cancel: cancelRequest
}
export default http