Vue.js 2:解决axios拦截器中Vuex Store导入为undefined的问题
你遇到的这个问题大概率是模块循环依赖导致的——当你的http.js导入store时,store模块可能还没完成初始化(比如你的store里的action又导入了这个axios实例),所以拿到的是undefined。另外还要提一句,你的请求拦截器代码里忘了返回config,这会导致请求无法正常发送,这个小细节也得补上。
先看看你的原始代码:
你的src/plugins/http.js代码
import Vue from 'vue' import store from '../store' import axios from 'axios' axios.interceptors.request.use( (config) => { if (store.getters['auth/hasAccessToken']) { config.headers['Authorization'] = 'Bearer ' + store.getters['auth/accessToken'] } // 这里缺少return config!拦截器必须返回配置对象 } );
你的src/store/index.js代码
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); export default new Vuex.Store({ //... 你的模块配置 });
下面给你几个可行的解决方案:
方案一:通过Vue原型上的$store获取(最推荐)
既然你已经在Vue实例中注入了store,那么可以直接通过Vue.prototype.$store来访问,这样就能避开循环依赖的问题。修改你的http.js:
import Vue from 'vue' import axios from 'axios' axios.interceptors.request.use( (config) => { // 直接通过Vue原型获取store if (Vue.prototype.$store?.getters['auth/hasAccessToken']) { config.headers['Authorization'] = 'Bearer ' + Vue.prototype.$store.getters['auth/accessToken'] } // 一定要返回config! return config; } );
注意:要确保这段代码执行时,Vue实例已经完成了store的注入(也就是在main.js里先挂载store,再导入http插件)。
方案二:调整导入顺序,避免循环依赖
如果你的store模块里确实导入了这个axios实例(比如在action里发请求),那可以调整main.js里的导入顺序,让store先被初始化完成,再导入http插件:
// main.js import Vue from 'vue' import store from './store' // 先导入并初始化store import './plugins/http' // 再导入http插件,此时store已经存在 import App from './App.vue' new Vue({ store, render: h => h(App) }).$mount('#app')
这种情况下,你原来的import store from '../store'就能正常拿到实例了,记得补上return config就行。
方案三:把store改成延迟导出(可选)
如果前两种方案都不适合,你可以把store的导出改成函数形式,延迟实例化:
// src/store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex); export default function createStore() { return new Vuex.Store({ //... 你的模块配置 }); }
然后在main.js里创建store实例,再把它传入http.js:
// main.js import Vue from 'vue' import createStore from './store' import axios from './plugins/http' import App from './App.vue' const store = createStore() // 把store传给axios实例 axios.defaults.store = store new Vue({ store, render: h => h(App) }).$mount('#app')
然后在http.js里通过axios.defaults.store访问:
// src/plugins/http.js import axios from 'axios' axios.interceptors.request.use( (config) => { const store = axios.defaults.store if (store.getters['auth/hasAccessToken']) { config.headers['Authorization'] = 'Bearer ' + store.getters['auth/accessToken'] } return config; } );
这个方案稍微复杂一点,一般前两种就够用了。
最后再提醒一句:不管用哪种方案,请求拦截器一定要返回config对象,否则axios会认为你取消了请求,导致请求发不出去。
内容的提问来源于stack exchange,提问作者D.R.

