Nuxt.js 请求域名变量管理:从配置到实践的完整指南

一、为什么需要管理请求域名变量?

在现代化Web开发中,前端应用通常需要同时支持开发、测试、预发布和生产等多个环境。每个环境对应的API域名、CDN地址或第三方服务端点往往不同。传统硬编码方式会导致以下问题:

  1. 环境切换困难:每次部署需要手动修改代码中的域名
  2. 维护成本高:相同配置在多个文件中重复出现
  3. 安全隐患:敏感域名信息可能被意外提交到版本控制系统

Nuxt.js作为基于Vue的服务器端渲染框架,其独特的运行环境(服务端+客户端)对域名管理提出了更高要求。例如,在服务端渲染时需要确保axios请求的域名与当前环境匹配,而在客户端导航时又要保持一致性。

二、Nuxt.js环境变量配置基础

1. 官方推荐方案:runtimeConfig

Nuxt 3+推荐使用runtimeConfig实现环境变量注入:

  1. // nuxt.config.ts
  2. export default defineNuxtConfig({
  3. runtimeConfig: {
  4. public: {
  5. apiBase: process.env.API_BASE || 'https://api.default.com'
  6. },
  7. apiSecret: process.env.API_SECRET // 仅服务端可用
  8. }
  9. })
  • public开头的变量会自动注入到客户端
  • 非public变量仅在服务端可用
  • 通过useRuntimeConfig()组合式API访问

2. 环境文件管理

创建.env文件(需添加到.gitignore):

  1. # .env.development
  2. API_BASE=https://api.dev.example.com
  3. # .env.production
  4. API_BASE=https://api.prod.example.com

配合dotenv插件自动加载对应环境的变量:

  1. # 启动时指定环境
  2. nuxt dev --mode development

三、动态域名管理的高级实践

1. 基于路由的动态域名切换

实现根据子域名自动切换API基础路径:

  1. // plugins/domain-router.ts
  2. export default defineNuxtPlugin((nuxtApp) => {
  3. const route = useRoute()
  4. const config = useRuntimeConfig()
  5. const domainMap = {
  6. 'dev': config.public.apiDevBase,
  7. 'staging': config.public.apiStagingBase
  8. }
  9. const currentDomain = domainMap[route.host.split('.')[0]] || config.public.apiBase
  10. nuxtApp.provide('apiDomain', currentDomain)
  11. })

2. 请求拦截器集成

创建统一的axios实例并注入动态域名:

  1. // composables/useApi.ts
  2. export const useApi = () => {
  3. const config = useRuntimeConfig()
  4. const $apiDomain = inject('apiDomain') || config.public.apiBase
  5. const api = useNuxtApp().$axios.create({
  6. baseURL: $apiDomain,
  7. timeout: 5000
  8. })
  9. // 请求拦截器
  10. api.onRequest((config) => {
  11. config.headers.Authorization = `Bearer ${useCookie('token').value}`
  12. })
  13. return api
  14. }

3. 服务端渲染的特殊处理

在服务端渲染时,需要确保域名解析与客户端一致:

  1. // server/api/example.get.ts
  2. export default defineEventHandler(async (event) => {
  3. const config = useRuntimeConfig()
  4. const nuxtApp = useNuxtApp()
  5. // 显式传递域名或从请求头获取
  6. const domain = event.node.req.headers['x-api-domain'] || config.public.apiBase
  7. const response = await $fetch(`${domain}/api/data`, {
  8. headers: {
  9. 'x-requested-with': 'nuxt-ssr'
  10. }
  11. })
  12. return response
  13. })

四、安全与最佳实践

1. 敏感信息保护

  • 永远不要将API密钥等敏感信息放在public配置中
  • 使用Nuxt的privateRuntimeConfig存储服务端专用变量
  • 考虑使用Vault等秘密管理工具

2. 类型安全增强

为环境变量创建TypeScript类型:

  1. // types/env.d.ts
  2. declare module '#env' {
  3. interface PublicEnv {
  4. apiBase: string
  5. cdnBase: string
  6. }
  7. interface PrivateEnv {
  8. apiSecret: string
  9. }
  10. }

3. 跨环境测试策略

  1. 开发环境:使用Mock Service Worker拦截请求
  2. 测试环境:配置与生产相同的域名结构但指向测试API
  3. 预发布环境:使用生产域名的子域名(如pre.example.com

五、实际项目中的完整示例

1. 配置结构

  1. .
  2. ├── nuxt.config.ts
  3. ├── .env.development
  4. ├── .env.production
  5. ├── plugins/
  6. └── api-client.ts
  7. ├── composables/
  8. └── useApi.ts
  9. └── server/
  10. └── api/
  11. └── proxy.ts

2. 核心实现代码

  1. // plugins/api-client.ts
  2. export default defineNuxtPlugin((nuxtApp) => {
  3. const config = useRuntimeConfig()
  4. // 动态域名解析逻辑
  5. const resolveDomain = () => {
  6. if (process.server) {
  7. // 服务端从请求头或配置获取
  8. return config.apiBase
  9. }
  10. // 客户端从存储或配置获取
  11. return localStorage.getItem('apiDomain') || config.public.apiBase
  12. }
  13. const api = useNuxtApp().$axios.create({
  14. baseURL: resolveDomain(),
  15. withCredentials: true
  16. })
  17. nuxtApp.provide('api', api)
  18. })
  19. // composables/useApi.ts
  20. export const useCustomApi = () => {
  21. const api = inject('api')
  22. const getData = async (endpoint: string) => {
  23. try {
  24. const response = await api.$get(endpoint)
  25. return response
  26. } catch (error) {
  27. console.error('API Error:', error)
  28. throw error
  29. }
  30. }
  31. return { getData }
  32. }

3. 页面组件使用示例

  1. <script setup>
  2. const { getData } = useCustomApi()
  3. const data = ref(null)
  4. onMounted(async () => {
  5. try {
  6. data.value = await getData('/users')
  7. } catch (error) {
  8. // 错误处理
  9. }
  10. })
  11. </script>

六、常见问题解决方案

1. 客户端与服务端域名不一致

问题:SSR时服务端请求成功,但客户端请求失败
解决方案

  1. // nuxt.config.ts
  2. export default defineNuxtConfig({
  3. nitro: {
  4. prerender: {
  5. routes: ['/'] // 确保预渲染路由使用正确域名
  6. }
  7. }
  8. })

2. 环境变量未生效

检查清单

  1. 变量名是否以NUXT_PUBLIC_开头(Nuxt 3)
  2. 是否在正确的.env文件中定义
  3. 是否重启了开发服务器
  4. 是否在runtimeConfig中正确定义了结构

3. CORS问题处理

服务端配置示例

  1. // server/middleware/cors.ts
  2. export default defineEventHandler((event) => {
  3. setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
  4. setResponseHeader(event, 'Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE')
  5. })

七、性能优化建议

  1. 域名预热:在应用启动时提前解析DNS
  2. 连接复用:配置axios的keepAlive选项
  3. 智能重试:实现指数退避算法处理临时故障
  4. 本地缓存:对不频繁变更的API响应使用Service Worker缓存

通过系统化的域名变量管理,Nuxt.js应用可以实现真正的环境无关部署,显著提升开发效率和运行稳定性。建议结合CI/CD流程,将环境配置作为部署流水线的一部分自动处理,进一步降低人为错误风险。