使用 vuex 在 vue/axios 中处理全局 http 响应错误

dev*_*man 8 javascript vue.js axios vuex vuejs2

我正在尝试修复 VueJS SPA 中出现边缘状态的行为。应用程序不知道 JWT 已过期,因此会显示为用户仍处于登录状态。例如,这可能会在休眠后发生。

这些用户可以继续向 API发出任何401请求,但最终会得到响应(而且是正确的)。

我想要一个全局401响应处理程序。(这将是:“从 vuex 中清除所有与用户相关的内容,并像用户是访客一样显示页面,并弹出登录表单等。”)否则,我将不得不为每个请求编写一个 401 处理程序。

我可以向 axios 添加响应拦截器,它们工作得很好。不过,这些拦截器无法访问 Vuex(或 Vue)。

每当我尝试将 Vuex 或 Vue 导入到我的 Axios 中时,我都会得到循环依赖(当然)并且一切都会崩溃。

如果我只是抛出/返回错误,我仍然必须对每个请求单独处理它。如何this.$store从 axios 拦截器内分派方法?

Axios 文件包含一个export default class API全局添加到 Vue 的文件main.js

import api from 'Api/api'
// ...
Vue.prototype.$http = api
Run Code Online (Sandbox Code Playgroud)

我原以为必须有一种方法可以访问Vuefrom $http,因为它是一个全局实例方法。但我好像误会了?

代码

main.js

// ...
import api from 'Api/api'
// ...
Vue.prototype.$http = api

new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App },
  vuetify: new Vuetify(opts),
});

Run Code Online (Sandbox Code Playgroud)

api.js

import Client from './ApiClient'

const apiClient = new Client({ basePath: process.env.VUE_APP_API_URL })

const api = {
  get(url) {
    return apiClient._get(`${basePath}/${url}`)
  },
  post(url, data) {
    return apiClient._post(`${basePath}/${url}`, data)
  },
  // ...
}
export default api

Run Code Online (Sandbox Code Playgroud)

ApiClient.js

const axios = require('axios')

const errorHandler = (error) => {
  if (error.response.status === 401) {
    store.dispatch('user/logout') // here is the problem
  }
  return Promise.reject({ ...error })
}


export default class API {
  constructor(options) {
    this.options = Object.assign({ basePath: '' }, options)
    this.axios = axios.create({ timeout: 60000 })
    this.axios.interceptors.response.use(
      response => response,
      error => errorHandler(error)
    )
  }
  // ...
}
Run Code Online (Sandbox Code Playgroud)

导入 store 会ApiClient.js导致依赖循环:我假设是因为我在其中导入了 Vue?

商店.js

import Vue from 'vue'
import Vuex from 'vuex'
import PersistedState from 'vuex-persistedstate'
import CreateMutationsSharer from 'vuex-shared-mutations';
import SecureLS from 'secure-ls';
// import modules

Vue.use(Vuex);
const ls = new SecureLS({ encodingType: 'aes' });

export default new Vuex.Store({
  // options
})
Run Code Online (Sandbox Code Playgroud)

小智 1

直接将您的商店导入 ApiClient.js 怎么样?就像是

const axios = require('axios')
import store from 'path/to/store'

const errorHandler = (error) => {
if (error.response.status === 401) {
  store.dispatch('user/logout') // now store should be accessible
}
  return Promise.reject({ ...error })
}


export default class API {
  constructor(options) {
    this.options = Object.assign({ basePath: '' }, options)
    this.axios = axios.create({ timeout: 60000 })
    this.axios.interceptors.response.use(
      response => response,
      error => errorHandler(error)
    )
  }
  // ...
}
Run Code Online (Sandbox Code Playgroud)