zoukankan      html  css  js  c++  java
  • 六、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)
                  }
                }
              )
  • 相关阅读:
    手把手玩转win8开发系列课程(5)
    一道百度之星编程大赛题的随笔联想·(2)
    手把手玩转win8开发系列课程(7)
    手把手玩转win8开发系列课程(10)
    一道百度之星编程大赛题的随笔联想·(1)
    手把手玩转win8开发系列课程(6)
    手把手玩转win8开发系列课程(9)
    手把手玩转win8开发系列课程(3)
    Innodb 表修复
    NoSQL之【Redis】学习(二):配置说明
  • 原文地址:https://www.cnblogs.com/fger/p/12710018.html
Copyright © 2011-2022 走看看