当您运行 npm run generate 生成静态页面时,Vite 的代理服务器确实无法使用,因为生成阶段是在 Node.js 环境中执行的构建过程。但别担心,我将为您提供一套完整的解决方案来处理构建阶段的跨域问题。
核心解决方案
1. 构建阶段:使用服务端中转 API(推荐)
在构建阶段通过 Nuxt 的 server 路由中转请求,避开跨域限制:
// server/api/products.ts
export default defineEventHandler(async (event) => {
// 从环境变量获取API地址
const apiBase = useRuntimeConfig().public.apiBase
// 构建阶段直接调用API(无跨域问题)
return await $fetch(`${apiBase}/products`, {
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`
}
}).catch(() => ([])) // 添加错误处理
})
为什么 server/api/products.ts是服务端中转 API?
文件位于 server/api 目录下,这是 Nuxt 3 中定义服务器端 API 的标准位置。
文件名为 products.ts,表示它处理的是与 /api/products 路径相关的请求
在这个处理函数中,它接收来自客户端的请求(在构建阶段,这个请求来自 Nuxt 的构建进程),然后它自己作为客户端去请求另一个后端服务(${apiBase}/products)。
这个后端服务可能是你真正的业务 API,可能运行在另一个域名或端口上(比如 http://localhost:3001 或 https://api.example.com)。
在构建阶段(npm run generate),Nuxt 是在 Node.js 环境中运行的,所以它直接发起 HTTP 请求(使用 $fetch)到后端服务,这不存在浏览器的同源策略限制(跨域问题只存在于浏览器中)。
在开发阶段,我们通过 Vite 的代理配置(在 nuxt.config.ts 中)将客户端对 /api/products 的请求代理到真正的后端服务,同样避免了浏览器的跨域问题。
2. 页面组件中调用中转 API
<!-- pages/products.vue -->
<script setup>
// 构建时调用的中转API(不存在跨域问题)
const { data: products } = await useAsyncData(
'products',
() => $fetch('/api/products')
)
</script>
当 Nuxt.js 执行 $fetch('/api/products') 时,它会自动匹配并调用 server/api/products.ts 中定义的中转 API 处理程序。这是一个 Nuxt.js 的核心约定机制。
详细的路径匹配规则:
目录结构映射:
- 所有放在
server/api/
目录下的 .ts 文件都会自动注册为 API 端点 - 文件路径直接对应路由路径:
具体匹配过程:
文件路径 | 对应的API路由 |
server/api/products.ts | /api/products |
server/api/products/index.ts | /api/products |
server/api/products/[id].ts | /api/products/:id |
server/api/categories/featured.ts | /api/categories/featured |
在页面中调用:
// 调用以下路径的API:
$fetch('/api/products') | server/api/products.ts |
$fetch('/api/products/123') | server/api/products/[id].ts |
$fetch('/api/categories/featured') | server/api/categories/featured.ts |
处理函数约定:
- 每个文件必须导出
default defineEventHandler
作为请求处理函数 - Nuxt 自动将请求路由到对应的处理程序
- 每个文件必须导出
// server/api/products.ts
export default defineEventHandler(async (event) => {
// 所有对 /api/products 的请求都会到达这里
})
3. 配置环境变量
# .env.production
NUXT_PUBLIC_API_BASE=https://production-api.com
API_TOKEN=your_prod_token
# .env.development
NUXT_PUBLIC_API_BASE=http://localhost:3000
4,开发环境 Vite 代理配置
// nuxt.config.ts
export default defineNuxtConfig({
vite: {
server: {
proxy: {
// 开发环境代理配置
'/api/': {
target: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:3000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api\//, '')
}
}
}
},
// 通用配置
runtimeConfig: {
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE
}
}
})
5.构建阶段工作流程详解
构建流程 (npm run generate)
│
├─ 1. 加载 nuxt.config.ts
│ 读取 runtimeConfig.public.apiBase
│
├─ 2. 扫描 pages/ 目录
│ 识别出需要使用数据的页面
│
├─ 3. 执行页面中的 useAsyncData/useFetch
│ → 调用 /api/products
│ ↓
├─ 4. 路由到 server/api/products.ts
│ → 使用 $fetch 访问外部 API
│ ↓
├─ 5. 获取数据 → 渲染页面 → 生成静态HTML
│
└─ 6. 输出静态文件到 .output/public