Глобальная обработка ошибок HTTP-ответа в vue / ax ios с помощью vuex - PullRequest
1 голос
/ 05 мая 2020

Я пытаюсь исправить поведение в моем vue SPA, которое, по сути, является неопределенным состоянием, когда приложение не знает, что срок действия JWT уже истек, и поэтому представляет себя так, как будто пользователь все еще вошел в систему. (Это происходит, например, после гибернации)

Эти пользователи могут продолжать делать любые запросы к API, но в конечном итоге, конечно же, получают 401 ответ

Теперь я бы хотелось бы иметь глобальный обработчик для 401 ответов. (это будет: "очистить все, что связано с пользователем, из vuex и представить страницу, как если бы пользователь был гостем, с всплывающим окном формы входа и т. д. c"), иначе мне пришлось бы написать обработчик 401 для КАЖДОГО запроса

проблема в том, что я могу добавить перехватчики ответа к ax ios, и они работают нормально. НО у них нет доступа к vuex (или Vue).

Всякий раз, когда я пытаюсь импортировать vuex или Vue в свой топор ios, я получаю круговые зависимости (конечно), и все ломается .

Если я просто выброшу / верну ошибку, мне все еще придется обрабатывать ее отдельно для каждого запроса.

Как я могу отправлять методы на this.$store из топора ios перехватчик?

(подробнее :) файл ax ios содержит export default class API

, который добавляется к Vue глобально в main. js через

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

так что я думал должен быть способ получить доступ к Vue из $http, поскольку это глобальный метод экземпляра ... я ошибаюсь?

как могу ли я решить эту проблему?

Код (насколько это возможно и актуально):

основной. 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)
    )
  }
  // ...
}

обновление

импорт хранилища в ApiClient. js приводит к циклу зависимости. я действительно не знаю почему, но я предполагаю, потому что я импортирую Vue в него?

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

Если вы нужна дополнительная информация, просто спросите :)

Спасибо за любую помощь

Ответы [ 2 ]

1 голос
/ 02 июня 2020

main. js:

import store from './store';

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

export const { $store } = Instance;

Теперь вы можете import { $store } from '@/main.js' где угодно. И это будет тот же экземпляр, который вы установили в своем приложении, а не new Vuex.Store({}) (который экспортирует ./store каждый раз, когда вы импортируете его в другое место).

Вы можете экспортировать таким же образом все, что вы, возможно, захотите использовать в службах, тестах, помощниках и т. Д. c ... То есть:

export const { $store, $http, $bus, $t } = Instance;
0 голосов
/ 05 мая 2020

А как насчет прямого импорта вашего магазина в 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)
    )
  }
  // ...
}
...