六、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)
              }
            }
          )
原文地址:https://www.cnblogs.com/fger/p/12710018.html