一、为什么需要管理请求域名变量?
在现代化Web开发中,前端应用通常需要同时支持开发、测试、预发布和生产等多个环境。每个环境对应的API域名、CDN地址或第三方服务端点往往不同。传统硬编码方式会导致以下问题:
- 环境切换困难:每次部署需要手动修改代码中的域名
- 维护成本高:相同配置在多个文件中重复出现
- 安全隐患:敏感域名信息可能被意外提交到版本控制系统
Nuxt.js作为基于Vue的服务器端渲染框架,其独特的运行环境(服务端+客户端)对域名管理提出了更高要求。例如,在服务端渲染时需要确保axios请求的域名与当前环境匹配,而在客户端导航时又要保持一致性。
二、Nuxt.js环境变量配置基础
1. 官方推荐方案:runtimeConfig
Nuxt 3+推荐使用runtimeConfig实现环境变量注入:
// nuxt.config.tsexport default defineNuxtConfig({runtimeConfig: {public: {apiBase: process.env.API_BASE || 'https://api.default.com'},apiSecret: process.env.API_SECRET // 仅服务端可用}})
- public开头的变量会自动注入到客户端
- 非public变量仅在服务端可用
- 通过
useRuntimeConfig()组合式API访问
2. 环境文件管理
创建.env文件(需添加到.gitignore):
# .env.developmentAPI_BASE=https://api.dev.example.com# .env.productionAPI_BASE=https://api.prod.example.com
配合dotenv插件自动加载对应环境的变量:
# 启动时指定环境nuxt dev --mode development
三、动态域名管理的高级实践
1. 基于路由的动态域名切换
实现根据子域名自动切换API基础路径:
// plugins/domain-router.tsexport default defineNuxtPlugin((nuxtApp) => {const route = useRoute()const config = useRuntimeConfig()const domainMap = {'dev': config.public.apiDevBase,'staging': config.public.apiStagingBase}const currentDomain = domainMap[route.host.split('.')[0]] || config.public.apiBasenuxtApp.provide('apiDomain', currentDomain)})
2. 请求拦截器集成
创建统一的axios实例并注入动态域名:
// composables/useApi.tsexport const useApi = () => {const config = useRuntimeConfig()const $apiDomain = inject('apiDomain') || config.public.apiBaseconst api = useNuxtApp().$axios.create({baseURL: $apiDomain,timeout: 5000})// 请求拦截器api.onRequest((config) => {config.headers.Authorization = `Bearer ${useCookie('token').value}`})return api}
3. 服务端渲染的特殊处理
在服务端渲染时,需要确保域名解析与客户端一致:
// server/api/example.get.tsexport default defineEventHandler(async (event) => {const config = useRuntimeConfig()const nuxtApp = useNuxtApp()// 显式传递域名或从请求头获取const domain = event.node.req.headers['x-api-domain'] || config.public.apiBaseconst response = await $fetch(`${domain}/api/data`, {headers: {'x-requested-with': 'nuxt-ssr'}})return response})
四、安全与最佳实践
1. 敏感信息保护
- 永远不要将API密钥等敏感信息放在
public配置中 - 使用Nuxt的
privateRuntimeConfig存储服务端专用变量 - 考虑使用Vault等秘密管理工具
2. 类型安全增强
为环境变量创建TypeScript类型:
// types/env.d.tsdeclare module '#env' {interface PublicEnv {apiBase: stringcdnBase: string}interface PrivateEnv {apiSecret: string}}
3. 跨环境测试策略
- 开发环境:使用Mock Service Worker拦截请求
- 测试环境:配置与生产相同的域名结构但指向测试API
- 预发布环境:使用生产域名的子域名(如
pre.example.com)
五、实际项目中的完整示例
1. 配置结构
.├── nuxt.config.ts├── .env.development├── .env.production├── plugins/│ └── api-client.ts├── composables/│ └── useApi.ts└── server/└── api/└── proxy.ts
2. 核心实现代码
// plugins/api-client.tsexport default defineNuxtPlugin((nuxtApp) => {const config = useRuntimeConfig()// 动态域名解析逻辑const resolveDomain = () => {if (process.server) {// 服务端从请求头或配置获取return config.apiBase}// 客户端从存储或配置获取return localStorage.getItem('apiDomain') || config.public.apiBase}const api = useNuxtApp().$axios.create({baseURL: resolveDomain(),withCredentials: true})nuxtApp.provide('api', api)})// composables/useApi.tsexport const useCustomApi = () => {const api = inject('api')const getData = async (endpoint: string) => {try {const response = await api.$get(endpoint)return response} catch (error) {console.error('API Error:', error)throw error}}return { getData }}
3. 页面组件使用示例
<script setup>const { getData } = useCustomApi()const data = ref(null)onMounted(async () => {try {data.value = await getData('/users')} catch (error) {// 错误处理}})</script>
六、常见问题解决方案
1. 客户端与服务端域名不一致
问题:SSR时服务端请求成功,但客户端请求失败
解决方案:
// nuxt.config.tsexport default defineNuxtConfig({nitro: {prerender: {routes: ['/'] // 确保预渲染路由使用正确域名}}})
2. 环境变量未生效
检查清单:
- 变量名是否以
NUXT_或PUBLIC_开头(Nuxt 3) - 是否在正确的
.env文件中定义 - 是否重启了开发服务器
- 是否在
runtimeConfig中正确定义了结构
3. CORS问题处理
服务端配置示例:
// server/middleware/cors.tsexport default defineEventHandler((event) => {setResponseHeader(event, 'Access-Control-Allow-Origin', '*')setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE')})
七、性能优化建议
- 域名预热:在应用启动时提前解析DNS
- 连接复用:配置axios的
keepAlive选项 - 智能重试:实现指数退避算法处理临时故障
- 本地缓存:对不频繁变更的API响应使用Service Worker缓存
通过系统化的域名变量管理,Nuxt.js应用可以实现真正的环境无关部署,显著提升开发效率和运行稳定性。建议结合CI/CD流程,将环境配置作为部署流水线的一部分自动处理,进一步降低人为错误风险。