我转过几个弯 绕过那个小雨楼
拿着蒲扇摆着衣衫渡着紧箍咒
不问天涯不停留 喝过几壶酒
不过年少白头道义放胸口
倘若明天之后 遥看前尘剑封侯
似那天上神仙无所求
朝朝暮暮君如梦醒十分不为何理由
是真是假是惶恐是无休
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
又过了几个弯 算尽天量道莫慌
踏这田园闻这芳草香
跌跌撞撞仗剑天涯折煞不枉无笔良
是梦是幻是温柔是家乡
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
路过这风雨花满楼 片刻都不停留
我本这书生进京赶考留下许多愁
你问有没有时候 我叹这天道默悠悠
能否与我一醉方休
谁能与我一醉方休
如何取消axios请求以及取消后错误处理的思路
前端在api请求的时候,有时候可能会遇到发送多个请求的时候,但是实际有效的是最后一次,但是后端响应的值不一定是你最后一次发送的请求,有可能最后一次比之前的还要更快响应,这就导致用户切换到a数据,前端显示是b数据。
解决这个情况有很多种方式,比如改动api请求方式,或者请求如果重复同一个接口,取消前面的请求,发起新的请求。
这里我们是后者。
使用方式
官方提供了两个例子,第一个例子照着写怎么都没用,第二个没看懂他的参数到底是data的还是谁的,最终还是百度了好多文章,才渐渐明白。
首先,我的项目使用的axios是二次封装的,也就是通过axios.create()
方法预设了baseURL和拦截器的,最终再导出,就是axios.create()
创建的实例。其他axios方式我就没空测了,可以看完本教程,在自行根据代码调整。
那么这个封装和导出,简单来说可以这么看:
request.js
import axios from "axios";
let api = axios.create({
...
});
export default api;
然后我的实际api请求是这样的
api-xxx.js
import api from "@/utils/request";
export const apiData = (data) => {
return api({
url: '/xxx/xx/xxx',
method: 'post',
data
});
};
我们现在就要对着api的请求进行调整,添加一个cancelToken参数,这个参数必须要引用axios对象来创建。
增加cancelToken参数
api-xxx.js
import api from "@/utils/request";
import axios from 'axios'
export const apiData = (data,that) => {
return api({
url: '/xxx/xx/xxx',
method: 'post',
data,
cancelToken: new axios.CancelToken(function executor(c) { // 设置 cancel token
that.cancel = c;
})
});
};
我们给apiData增加了一个that参数,这个参数用于获取到api所使用的vue文件的上下文对象,我们给他的上下文对象cancel设置了一个方法c,c就是用于取消本次请求的方法。
vue中使用
<template>
...
</template>
<script>
import { apiData } from "@/api/api-xxx";
export default {
data(){
return {
cancel: null, //取消请求
}
},
methods:{
//请求
getApiData(){
//判断取消方式是否存在,存在说明在这之前已经发请了请求
if(typeof this.cancel === "function") {
this.cancel("取消本次请求");
};
//发起请求
apiData({key:value},this).then(res=>{
...
}).catch(err=>{
...
})
}
}
}
</script>
这样就行了,每次发请求都都会先判断上一次是否有请求,有的话取消,但是上一次请求可能会很早就发出的,再取消也无所谓,所以不用再判断间隔啥的。
this.cancel("取消本次请求")
中的参数,可传可不传,就是一个文字mssage而已,无妨。
错误处理
取消请求,其实走的是promise的错误处理,也就是说,取消本次请求后,会触发api的interceptors.response
拦截器的错误处理,也就是如下代码所示:
import axios from "axios";
let api = axios.create({
...
});
api.interceptors.response.use(response => {},error=>{
//触发这个错误处理
})
export default api;
其中error并不是一个真正意义上的Error对象,他是一个axios生成的一个对象,本身也不是有code值这些,他的对象如下:
Cancel {message: undefined}
如果我们在this.cancel
方法中传入一个值,那么undefined就是这个值了。
但是取消的请求我们并不需要进行错误提示,因为他并不是一个真正的错误,好在axios官方提供了一个判断方法
import axios from "axios";
let api = axios.create({
...
});
api.interceptors.response.use(response => {},error=>{
//触发这个错误处理
if(!axios.isCancel(error)){
...统一的错误通知
};
return Promise.reject(error);
})
export default api;
本身是一个promise,所以我们忽略在取消请求时的统一错误通知方法,但是还是要抛出一个错误给vue文件中apiData
请求的catch。
这里其实有两个路子:
- 原封不动的返回error对象
- 自己封装一个对象用于判断
我选的第一条,简单点。
一般来说,我们在安装完axios会在main.js中将axios注册在vue的原型链上。
main.js
import Vue from "vue";
//axios
import axios from "axios";
Vue.prototype.$axios = axios;
所以我们在apiData
请求的catch中可以这么写
<template>
...
</template>
<script>
import { apiData } from "@/api/api-xxx";
export default {
data(){
return {
cancel: null, //取消请求
}
},
methods:{
//请求
getApiData(){
//判断取消方式是否存在,存在说明在这之前已经发请了请求
if(typeof this.cancel === "function") {
this.cancel("取消本次请求");
};
//发起请求
apiData({key:value},this).then(res=>{
...
}).catch(err=>{
if (this.$axios.isCancel(err)) return;
...省略自己的错误处理方法
})
}
}
}
</script>
直接在catch中判断一下,是取消就return跳过就行了。
效果图
取消错误的补充
axios的请求取消后,会触发到error回调,对于这个回调的error参数对象,axios本身提供了一个isCancel()
的方法判断。
一般来说我们都会在这个error回调里面抛出一个Promise.reject();
api.interceptors.response.use(response => {},error=>{
return Promise.reject(error);
})
但是这也会产生一个问题,就是如果发起api请求的那边,没有使用catch
捕获这个错误,那么promise会将这个错误直接全局抛出,也就是说会在浏览器的cosole那报错,但是并不影响代码运行。
在实际api请求那边,catch并不一定要做处理,可以是一个空的回调函数,也没必要在那边判断是否为取消。
上面我的说明有些偏面,但是也是一种思路,常用的话可能是这样:
//发起请求
apiData({key:value},this).then(res=>{
...
}).catch(()=>{
//不处理或者做其他的
})
我们也没必要每个请求的catch都去判断是否为取消的请求,其实没啥必要,只要不要写一些复杂的需求,为了不让他全局抛出错误,我们可以直接如上所示,写一个空的回调即可。
当然axios的issues中有提供了一个防止全局抛出错误的处理方式,但是呢,答者本人并不推荐,代码如下:
instance.interceptors.response.use((response) => {
if (someCondition(response) {
return new Promise(() => {});
}
return response;
});
他的原理就是,如果是一个取消请求的报错,那么就返回一个永远不会有结果的Promise,于是请求的then和catch都不会被触发,全局的报错就不会存在了。
但是,也会有一个问题,就是内存泄漏,当promise创建后,他就一直在pengding状态,一直在内存中常驻等待返回内容处理。
所以,如果是一个永远不会有结果的promise会让内存中常驻一个用不到的内容。但是又无法清除。
所以,对于取消产生的错误处理方式其实就两种:
- 每个请求都带catch捕获 (推荐使用的)
- 返回一个不会有结果的Promise (会造成内存泄漏)
以上就是关于axios取消请求以及取消后错误处理的方式思路。
评论(0)