Nuxt.js 实现axios插件访问store存储token的方法
Nuxt 自定义axios插件读取Store Token的正确实现
此前方案失效的核心原因
- 直接从store文件导入静态state的思路完全不匹配Nuxt的运行逻辑:Nuxt的store是运行时在服务端、客户端分别独立实例化的,静态导入拿到的不是实际运行的状态实例,自然读不到正确的值
- 插件入参解构store报错,本质是没有按照Nuxt插件的规范注册、执行:如果插件没有在
nuxt.config.js的plugins数组里正确登记,Nuxt不会在执行时传入包含store的上下文对象,自然会出现解构undefined的报错 - 在axios实例创建时硬编码
Authorization请求头是逻辑错误:插件初始化的执行时机早于用户登录、Store持久化数据从本地恢复的时机,这时候拿到的token大概率是null;就算后续Store里的token更新,已经固化在实例初始化配置里的请求头也不会同步更新 - 在mutation中调用
this.$axios.setHeader不生效,是因为没有把自定义的axios实例正确挂载到Nuxt全局上下文,此时的this.$axios要么不存在,要么不是你创建的目标实例,调用自然没有实际效果
正确实现步骤
1. 重写axios插件逻辑
核心调整点:
- 从Nuxt上下文解构获取store实例
- 通过请求拦截器在每次请求发出前动态读取最新的store token,而非硬编码在初始化配置里
- 将创建好的axios实例挂载到Nuxt全局上下文,方便组件内调用
示例代码:
// /plugins/axios.js import axios from 'axios' // 插件第二个入参是Nuxt提供的inject方法,用来挂载全局属性 export default ({ store }, inject) => { // 仅创建基础axios实例,不提前绑定固定的Authorization头 const api = axios.create({ baseURL: process.env.BASE_URL }) // 添加请求拦截器:每个请求发出前执行一次 api.interceptors.request.use(config => { // 读取当前最新的store token,存在则动态填充请求头 const token = store.state.token if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) // 将实例挂载到全局,后续可通过this.$api直接调用 inject('api', api) }
为什么必须用请求拦截器?因为插件初始化时机非常早:
- 客户端场景下,插件执行时持久化插件可能还没把本地存储里的token恢复到store里,这时候硬编码的请求头会是空的
- 后续用户登录、store更新token后,已经创建好的实例的静态配置不会自动同步
用拦截器的话,每次发请求才去读最新的store状态,永远能拿到当前最新的token值,不会出现状态不同步的问题
2. 调整nuxt.config.js的插件执行顺序
Nuxt会严格按照plugins数组的顺序从上到下执行插件,因为你用了客户端侧的store持久化插件,必须保证持久化插件的执行顺序在axios插件之前——不然axios拦截器执行时,store里的持久化token还没从本地恢复,会出现第一次请求拿不到token的问题。
正确配置:
// nuxt.config.js export default { plugins: [ // 先执行持久化插件,等store的本地数据恢复完成 '~/plugins/persistedState.client.js', // 再执行axios插件 '~/plugins/axios' ] }
3. 修正mutation中的请求头设置逻辑
因为现在已经把自定义的axios实例挂载到了全局上下文,你之前在mutation里写的setHeader逻辑只要调整下指向的实例,就可以正常生效:
// store/index.js export const state = () => ({ token: null, user: null, isUserLoggedIn: false }) export const mutations = { setToken(state, token) { state.token = token state.isUserLoggedIn = !!token // 这里的this.$api就是之前插件挂载的自定义axios实例 if (token) { this.$api.setHeader('Authorization', `Bearer ${token}`) } else { // 用户登出时主动清除请求头 this.$api.setHeader('Authorization', '') } } }
这部分逻辑属于双保险:因为有请求拦截器的动态读取,就算不写mutation里的setHeader,也能正常给每个请求带上最新的token,补上这段逻辑只是为了让实例的默认配置和store状态保持同步。
解构store报错的通用排查方向
如果写了解构逻辑还是报Cannot destructure property 'store' of 'undefined' as it is undefined,按以下顺序排查:
- 检查插件是否在
nuxt.config.js的plugins数组里正确登记,有没有写错文件路径 - 检查插件的导出格式是否符合Nuxt的规范:有没有把插件写成了普通业务组件的导出逻辑,没有按照插件的签名传入上下文
- 如果是Nuxt 3项目,需要匹配对应的插件写法:Nuxt 3不再支持直接通过插件入参解构store,需要通过
defineNuxtPlugin获取nuxtApp上下文,再从中取到对应的store实例
内容的提问来源于stack exchange,提问作者paddyfields
相关产品推荐
相关产品推荐

