Nuxt3如何在setup脚本外正确读取环境变量配置Axios实例
问题背景
需要在Pinia actions中调用后端服务接口,计划使用自定义Axios实例发起请求,存在以下已知限制:
- Nuxt3 内置
useFetch仅允许在组件setup脚本范围内调用 - 社区原有axios模块仅支持Nuxt2,与Nuxt3不兼容
当前已完成基础配置,运行时出现异常:服务端可正常读取环境变量,控制台输出正确变量值,但客户端侧运行报错,提示无法读取undefined的相关属性。
现有配置
nuxt.config.js 配置
import { defineNuxtConfig } from "nuxt"; export default defineNuxtConfig({ runtimeConfig: { public: { apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1", }, }, env: { apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1", }, buildModules: ["@pinia/nuxt"], });
Axios实例封装(instance.js)
import axios, { AxiosResponse } from "axios"; const instance = axios.create({ baseURL: process.env.API_BASE_URL, }); instance.interceptors.response.use((response: AxiosResponse) => { return response.data; }); export default instance;
问题根因
- Nuxt3 已废弃原Nuxt2版本的
env配置项,该配置不会向客户端注入任何环境变量 - 客户端打包后的代码不会自动注入服务端的
process.env变量,直接在普通JS模块顶层读取process.env的写法,在客户端侧执行时值为undefined - 只有配置在
runtimeConfig.public下的变量,才会被Nuxt序列化后同时暴露给服务端、客户端环境,且必须通过useRuntimeConfig()方法读取,不能直接访问process.env - Axios实例在模块顶层初始化时,Nuxt运行时上下文还未完成初始化,此时即使调用
useRuntimeConfig()也会报错
修复方案
第一步:清理nuxt.config.js冗余配置
删除废弃的env字段,新版Nuxt3中第三方模块统一放在modules数组中即可,无需使用buildModules:
import { defineNuxtConfig } from "nuxt"; export default defineNuxtConfig({ runtimeConfig: { public: { apiBase: process.env.API_BASE_URL ?? "http://localhost:8080/api/v1", }, }, modules: ["@pinia/nuxt"], });
第二步:改造Axios实例初始化逻辑
两种实现方式二选一即可:
方式1:通过Nuxt插件全局注入Axios实例(推荐)
新建plugins/axios.js文件,在插件生命周期内初始化实例,此时Nuxt上下文已就绪,可以正常读取runtimeConfig:
import axios from "axios"; export default defineNuxtPlugin(() => { const runtimeConfig = useRuntimeConfig(); const axiosInstance = axios.create({ baseURL: runtimeConfig.public.apiBase, }); axiosInstance.interceptors.response.use((response) => { return response.data; }); return { provide: { axios: axiosInstance } } });
在Pinia action中使用时,直接通过useNuxtApp获取注入的实例即可:
export const useUserStore = defineStore('user', { actions: { async fetchUserInfo() { const { $axios } = useNuxtApp(); const res = await $axios.get('/user/info'); // 业务逻辑 } } })
方式2:懒加载Axios实例
如果不想使用插件,可以把实例初始化逻辑封装为懒加载函数,避免在模块顶层执行:
修改原instance.js文件:
import axios from "axios"; let axiosInstance = null; export default function getAxios() { if (axiosInstance) return axiosInstance; const runtimeConfig = useRuntimeConfig(); axiosInstance = axios.create({ baseURL: runtimeConfig.public.apiBase, }); axiosInstance.interceptors.response.use((response) => { return response.data; }); return axiosInstance; }
在Pinia action中使用时,先调用方法获取实例再发起请求:
import getAxios from '~/utils/instance.js'; export const useUserStore = defineStore('user', { actions: { async fetchUserInfo() { const axios = getAxios(); const res = await axios.get('/user/info'); // 业务逻辑 } } })
注意:不要在普通JS模块的顶层调用
getAxios(),必须在组件setup、Pinia action、插件等存在Nuxt上下文的位置调用,否则会触发useRuntimeConfig的调用限制报错。
内容的提问来源于stack exchange,提问作者Victor Orlyk
相关产品推荐
相关产品推荐

