Global http response error handling in vue/axios with vuex
我正在尝试修复我的 VueJS SPA 中出现不确定状态的行为。应用程序不知道 JWT 已经过期,因此将自己显示为用户仍在登录。例如,这可能在hibernate后发生。
这些用户可以继续向 API 发出任何请求,但最终会得到
我想要一个用于
我可以向 axios 添加响应拦截器,它们工作正常。但是,这些拦截器无法访问 Vuex(或 Vue)。
每当我尝试将 Vuex 或 Vue 导入我的 Axios 时,我都会得到循环依赖(当然)并且一切都中断了。
如果我只是抛出/返回错误,我仍然需要在每个请求上单独处理它。如何从 axios 拦截器中在
Axios 文件包含一个
中全局添加到 Vue
1 2 3 | import api from 'Api/api' // ... Vue.prototype.$http = api |
我认为必须有一种方法可以从
代码
main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | // ... 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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) ) } // ... } |
在
store.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 }) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | conf import Axios from 'axios' import IdentityProxy from './IdentityProxy.js' import UsuariosProxi from './UsuariosProxi' import ZonasProxi from './ZonasProxi' //axios Axios.defaults.headers.common.Accept='application/json' //Axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*'; Axios.interceptors.request.use( config => { let token = localStorage.getItem('access_token'); if(token){ config.headers= { 'x-access-token': `${token}` } } return config; }, error => Promise.reject(error) ); Axios.interceptors.response.use( response => response, error => { if (error.response.status===403||error.response.status===401) { localStorage.removeItem('access_token'); window.location.reload(true); } return Promise.reject(error); } ); let url=null if(localStorage.getItem("config")!==null){ let config = JSON.parse(localStorage.getItem("config")) url = config } console.log(url) export default{ identityProxy: new IdentityProxy(Axios, url), _usuarioProxi: new UsuariosProxi(Axios, url), _zonasProxi: new ZonasProxi(Axios, url), } // export default class IdentityProxy{ constructor(axios,url){ this.axios = axios; this.url =url; } register(params){ return this.axios.post(this.url+'/identity/register',params) } login(params){ return this.axios.post(this.url+'/auth/signin',params) } } // export default class UsuariosProxi{ constructor(axios,url){ this.axios = axios; this.url =url; } /* getAll(){ return this.axios.get(this.url+'/users') } */ getAll(page, take) { return this.axios.get(this.url + `/users?page=${page}&take=${take}`); } create(params) { return this.axios.post(this.url + '/auth/signup', params); } get(id) { return this.axios.get(this.url + `/users/${id}`); } update(id, params) { return this.axios.put(this.url + `/users/${id}`, params); } remove(id) { return this.axios.delete(this.url + `/users/${id}`); } //-----APARTE SOLO TRAE LISTA DE ROLES-------- getRoles() { return this.axios.get(this.url + '/users/newrol'); } } //st import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const state = { user:null } export default new Vuex.Store({ state }); |
基于这些线程,我能够管理满足我需求的解决方案:
main.js
1 2 | import api, {apiConfig} from 'Api/api' apiConfig({ store: $store }); |
ApiClient.js
1 2 3 4 5 6 7 8 | let configs = { store: undefined, }; const apiConfig = ({ store }) => { configs = { ...configs, store }; }; export default api; export { apiConfig }; |
这样api.js文件就需要一个配置,以后可以扩展。
main.js:
1 2 3 4 5 6 7 8 | import store from './store'; const Instance = new Vue({ store, ... }) export const { $store } = Instance; |
现在您可以
您可以以相同的方式导出您可能想在服务、测试、帮助程序等中使用的任何其他内容...即:
1 | export const { $store, $http, $bus, $t } = Instance; |
直接将您的商店导入 ApiClient.js 怎么样?类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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) ) } // ... } |