六、axios拦截器扩展3
一、axios的请求与取消
欢迎大家去验证:后台加个Thread.sleep(3000);,可以模拟网络延迟
var vm=new Vue({ el:"#div_id", data:{ cancelTag:[], //装所有的想要准备移除的请求,用处:当你离开这个页面时,将取消这个页面发出 的未完成的所有请求 cancelCurrentTag:null, //放置的是前一个单独的请求,用处:有时只想对某一个可能未完成的请求,让它取消 }, methods:{ post:function(){ //post请求 var CancelToken = axios.CancelToken; //这里不写,下面new对象那里会报空 axios({ headers: { 'Content-Type': 'application/json' }, transformRequest: [function(data) { //请求之前,对数据做处理 data = JSON.stringify(data) return data }], timeout:5000, url: '***', method: 'post', //params: {}, data: { 'code': 123, //传的参数 'data': "***" }, // “cancelToken”指定可用于取消请求的取消令牌 cancelToken: new CancelToken(function (cancel) { vm.cancelCurrentTag=cancel; vm.cancelTag.push(cancel); //动态放入 }) }).then(function(res){ //想打出全部数据,可以使用console.log(JSON.stringify(err)),不会会显示object对象,而无法查看具体数据 console.log("请求数据:"+res.data) }).catch(function(err){ if(err!="Cancel"){ //非代码取消请求造成的异常,才输出显示 console.log("请求异常:"+err) } }) }, cancelAll:function(){ //取消之前的全部请求 $.each(this.cancelTag,function(i,item){ console.log("执行了") item(); }) this.cancelTag=[]; //取消完之后,再清空记录 }, cancel:function(){ console.log("执行") var j=-1; this.cancelCurrentTag(); $.each(this.cancelTag,function(i,item){ //既然准备单独取消,就将总体中的该部分移去 if(item==vm.cancelCurrentTag)j=i; }) if(j!=-1)this.cancelTag.splice(j,1); } } })
二、在路由切换时取消axios请求demo
<!DOCTYPE html > <html lang="en"> <head> <meta charset="UTF-8"> <title>在路由切换时取消axios请求demo</title> <!-- <script src="./库/vue.js"></script> <script src="./库/vue-router.js"></script> <script src="./库/axios.js"></script> --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router@3.1.3/dist/vue-router.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> <router-link to="/home">home</router-link> <router-link to="/about">About</router-link> <hr> <router-view></router-view> </div> </body> <script> const Home = { template: ` <div> <h3>Home</h3> <button @click="sendRequest(false)">发送一个不能取消的请求</button> </div> `, methods: { sendRequest } } function sendRequest(whetherCancel) { axios.get("http://localhost:3000/demo", { //添加cancel数据,在拦截器中通过判断cancel添加CancleToken params: { cancel: whetherCancel } }).then(res => { if (res.data.status === 200) { console.log("请求成功") } }).catch(err => { axios.isCancel(err) ? console.log("请求取消了") : console.log(err) }) } const About = { template: ` <div> <h3>About</h3> <button @click="sendRequest(true)">发送一个能取消的请求</button> </div> `, methods: { sendRequest } } const routes = [{ path: "/home", component: Home }, { path: "/about", component: About }] const CancelToken = axios.CancelToken; let cancel; const router = new VueRouter({ routes }) //拦截器 axios.interceptors.request.use(config=> { //在拦截器中给每一个带有params.cancel为ture的请求的添加cancelToken if(config.params.cancel){ config.cancelToken = new CancelToken(c => { cancel = c }) } return config; }, (error)=> { // Do something with request error return Promise.reject(error); }); //在路由守卫中通过source取消请求 router.beforeEach((to, from, next) => { cancel && cancel() next() }) new Vue({ el: "#app", router }) </script> </html>
三、借用Windows对象
在拦截器全局设置,用来取消所有请求:
import axios from "axios"; window.axiosCancel = [] // 全局定义一个存放取消请求的标识 const Axios = axios.create({ baseURL:"", timeout: 10000, ... }); //请求前拦截 Axios.interceptors.request.use(config => { return config // 添加取消标记 config.cancelToken = new axios.CancelToken(cancel => { window.axiosCancel.push({ cancel }) },function(error) { return Promise.reject(error) }); //请求后返回数据拦截 Axios.interceptors.response.use(res => { },function axiosRetryInterceptor(res) { return Promise.reject(res ) }); export default Axios
然后在组件中使用,发送一个新的请求之前,取消前面的所有正在请求的请求,如下:
methods:{ cancel(){ // 设置一个函数,在执行请求前先执行这个函数 // 获取缓存的 请求取消标识 数组,取消所有关联的请求 let cancelArr = window.axiosCancel; cancelArr.forEach((ele, index) => { ele.cancel("取消了请求") // 在失败函数中返回这里自定义的错误信息 delete window.axiosCancel[index] }) }, getList(){ this.cancel() // 取消所有正在发送请求的请求 axios.post(..) // 发送一个新的请求 } }
如果不希望每个组件里面都定义一个cancel函数,我们可以把这个函数挂载到vue实例的原型上,这样就可以在任何组件中使用cancel函数了:this.cancel(),如下main.js文件中:
import Vue from 'vue' import App from './App' import router from './router' import store from './store'//引入store Vue.config.productionTip = false // 将cancel,挂载到vue原型上 Vue.prototype.cancel = function(){ // 获取缓存的 请求取消标识 数组,取消所有关联的请求 let cancelArr = window.axiosCancel; cancelArr.forEach((ele, index) => { ele.cancel("取消了请求") // 在失败函数中返回这里自定义的错误信息 delete window.axiosCancel[index] }) } window.vm=new Vue({ el: '#app', data(){ return{ } }, router, store, components: { App }, })
另外如果想每次路由页面跳转时,取消上一个页面的所有请求,我们可以把cancel()函数的内容放在路由拦截器中,router/index.js文件配置,如下:
// 引入路由以及vue,下面的是固定写法,照写就可以 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) //创建路由实例 const router = new Router({ linkActiveClass: 'app-active', // 路由点击选中时的颜色(app-active为自定义的class样式类) routes: [ { // 根路径 path: '/', redirect: '/home', component: () => import('@/pages/home') // 路由懒加载写法 }, { path: '/home', name: 'home', component: () => import('@/pages/home'), } }) /* 路由拦截器 路由跳转前的操作 */ router.beforeEach((to, from, next) => { // 获取缓存的 请求取消标识 数组,取消所有关联的请求 let cancelArr = window.axiosCancel; cancelArr.forEach((ele, index) => { ele.cancel("取消了请求") // 在失败函数中返回这里自定义的错误信息 delete window.axiosCancel[index] }) next() }) /* 路由拦截器 路由跳转后的操作 */ router.afterEach(to => { }) // 将路由导出,供外部接收,主要用于main.js接收 export default router
四、借助全局对象
main.js
Vue.Cancel = [] //全局定义一个对象 router.beforeEach((to, from, next) => { while (Vue.Cancel.length > 0) { // 存储的对象进行abort() Vue.Cancel.shift().abort() } }
请求的地方加上
oneRequest = context.$http.post(url, newParams, //这里用的是vue-resource { // 发送请求前把request存放在Vue.Cancel对象中,为后面路由切换的时候中断使用 // use before callback before (request) { Vue.Cancel.push(request) } } )
点到为止