【问题标题】:Too many requests when controlling spinner show/hide from axois interceptors从 axios 拦截器控制微调器显示/隐藏时请求过多
【发布时间】:2018-01-21 14:09:18
【问题描述】:

我有一个用 Vue (Webpack) 编写的 SPA,我想根据应用当前是否正在处理 HTTP 请求或响应来控制微调器的可见性。

按照一些教程,我想出了事件总线方案并做到了:

创建eventBus.js:

import Vue from 'vue';
export const eventBus = new Vue();

我将我的 axios 拦截器设置在 App.vuecreated() 钩子中。以下是该组件中必要的功能:

data() {
        return {
            showLoader: false
        };
    },  

    created(){
        this.setAxiosInterceptors();
        // some code removed //            
        }
    },

    mounted() {
        eventBus.$on('show-loader', () => {
            this.showLoader = true;
        });

        eventBus.$on('hide-loader', () => {
            this.showLoader = false;
        });
    },

methods: {       
        setAxiosInterceptors() {
            var tokenCookieName = this.$store.getters.getCookieNames.apiToken;
            var cookieDefaultValue = this.$store.getters.getCookieDefaultValue;

            // token expired middleware
            this.axios.interceptors.response.use(response => {
                var data = response.data;

                if(data.info.api_token) {
                    this.$cookie.set(tokenCookieName, data.info.api_token);
                }

                if(data.status == 'error' && data.info.login_failed) {
                    this.$cookie.set(tokenCookieName, cookieDefaultValue);
                    window.location = '/'; // not possible to use Vue router here
                }

                eventBus.$emit('hide-loader');
                return response;
            }, 
                error => {
                    eventBus.$emit('hide-loader');                    
                    console.log('Response interception failed!');
                    return Promise.reject(error);
            });

            // attach API token middleware
            this.axios.interceptors.request.use(config => {
                var apiToken = this.$cookie.get(tokenCookieName);

                if (!apiToken) {
                    apiToken = cookieDefaultValue;
                }

                config.headers.Authorization = 'Bearer ' + apiToken;               
                eventBus.$emit('show-loader');               
                return config;
            }, 
                error => {
                    eventBus.$emit('hide-loader');
                    console.log('Request interception failed!');
                    return Promise.reject(error);                    
                }
            );
        }
    }

请忽略一些与问题无关的代码,但我想展示一下是如何设置的。问题是,当我访问我的主页时,应用程序会不断发出启动 GET 请求,直到我的服务器返回 429 错误。

有趣的是,在我的 eventBus.$on 处理程序中,如果我只是执行 console.log,则不会出现这种行为(当然,微调器也不能正常工作)但是一旦我更改了变量或调用 vuex 动作,无限重新加载开始

有什么线索吗?

【问题讨论】:

  • showLoader 是否与v-if 一起使用?
  • created 函数是否被重复调用,意味着组件正在被销毁和重新创建?
  • @RoyJ 是的,showLoader 用于确定 v-ifv-else 以有条件地显示/隐藏微调器。我不确定如何确定组件是否被反复破坏:如果其他因素导致浏览器反复重新加载,destroyed 函数仍将被调用。
  • 尝试将您的组件放在<keep-alive> 标签中。
  • @RoyJ 你的意思是把我的整个 if-else 包裹在 keep-alive 中还是只是微调器组件?

标签: vue.js axios


【解决方案1】:

main.js 文件中

Vue.prototype.$axios = axios.create(
  {
    headers:
      {
        'Content-Type': 'application/json',
      },
    baseURL: process.env.API_URL
  }
);

Vue.prototype.$axios.interceptors.request.use(
  config =>
  {
    eventBus.$emit('show_spin');
    let token = getTokenID();
    if(token && token.length) config.headers['Authorization'] = token;
    return config;
  },
  error =>
  {
    eventBus.$emit('hide_spin');
    if (error.status === 401) VueRouter.push('/login');
    else throw error;
  }
);
Vue.prototype.$axios.interceptors.response.use(
  response =>
  {
    eventBus.$emit('hide_spin');
    return response;
  },
  error =>
  {
    eventBus.$emit('hide_spin');
    return new Promise(function(resolve,reject)
    {
      if (error.config && error.response && error.response.status === 401 && !error.config.__isRetry)
      {
        myVue.refreshToken(function()
        {
          error.config.__isRetry = true;
          error.config.headers['Authorization'] = getTokenID();
          myVue.$axios(error.config).then(resolve,reject);
        },function(flag) // true = invalid session, false = something else
        {
          if(process.env.NODE_ENV === 'development') console.log('Could not refresh token');
          if(getUserID()) myVue.showFailed('Could not refresh the Authorization Token');
          reject(flag);
        });
      }
      else throw error;
    });
  }
);

let myVue = new Vue(
{
  el: '#app',
  data: function()
  {
    return {
      spin_visible: 0, // dynamically show/hide spinner
    };
  },
  created: function()
  {
    eventBus.$on('show_spin', this.showSpin);
    eventBus.$on('hide_spin', this.hideSpin);
  },
  methods:
  {
    showSpin: function()
    {
      this.spin_visible++;
    },
    hideSpin: function()
    {
      if(this.spin_visible>0) this.spin_visible--;
    }, 
    ....

然后在App.vue

<template>
  <router-view/>
  <div class="spinner" v-show="$root.spin_visible"> 
  <!-- define your spinner here -->
  </div>
</template>

【讨论】:

  • 嘿,你能解释一下这里的概念吗?我的意思是,我做错了什么?
  • 好的,想法是计数器spin_visible在每次请求前增加,每次请求后减少(不管成功与否)。仅当计数器非零时才会显示微调器。您不能在此处使用布尔值,因为如果在前一个请求完成之前启动另一个请求 - 第一个请求将在最终完成时重置布尔变量(而第二个请求仍处于活动状态)。如果 JWT 令牌已过期,该代码还会自动重试。
猜你喜欢
  • 2020-04-07
  • 1970-01-01
  • 2020-09-25
  • 2017-08-22
  • 2017-12-12
  • 2020-01-18
  • 2022-11-14
  • 2020-01-13
  • 1970-01-01
相关资源
最近更新 更多