Global http response error handling in vue/axios with vuex

会有一股神秘感。 提交于 2020-07-03 09:39:37

问题


I'm trying to fix a behavior in my vue SPA which is basically a limbo state where the app doesn't know the JWT is already expired and therefore presents itself as if the user was still logged in. (this happens after hibernation for example)

These users can keep on making any request to the API, but end up with a 401 response of course

Now I would like to have a global handler for 401 responses. (which would be: "clear everything user-related from vuex and present the page as if the user was a guest, with login form popup etc"), otherwise i would have to write a 401 handler for EVERY request

the problem being: I can add response interceptors to axios, and they work fine. BUT they don't have access to vuex (or Vue).

Whenever i try to import vuex or Vue into my axios, i get circular dependencies (of course) and everything breaks.

If i just throw/return the error, i will STILL have to handle it separately on every request.

How can i dispatch methods on this.$store from within an axios interceptor?

(more info:) the axios file contains an export default class API

which is added to Vue globally in main.js via

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

so i thought there has to be a way to access Vue from $http, since, it's a global instance method... am I wrong?

how can I solve it?

Code (as far as possible and relevant):

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),
});

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

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)
    )
  }
  // ...
}

update

importing store in ApiClient.js results in a dependency cycle. i don't really know why, but i assume because i'm importing Vue in it?

store.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
})

If you need any more info, just ask :)

Thanks for any help


回答1:


main.js:

import store from './store';

const Instance = new Vue({
  store,
  ...
})

export const { $store } = Instance;

Now you can import { $store } from '@/main.js' anywhere you want. And it's going to be the same instance you have mounted in your app, not a new Vuex.Store({}) (which is what ./store exports, each time you import it somewhere else).

You can export the same way anything else you might want to use in services, tests, helpers, etc... I.e:

export const { $store, $http, $bus, $t } = Instance;



回答2:


What about direct import your store to ApiClient.js? Something like

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)
    )
  }
  // ...
}


来源:https://stackoverflow.com/questions/61613545/global-http-response-error-handling-in-vue-axios-with-vuex

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!