Nuxt 3 SSR中useFetch客户端重复请求引发CORS问题排查
解决useFetch在SSR中使用.env变量引发的客户端CORS问题
问题根源
你设置了server: true但客户端仍发起请求,核心原因是:
- 非public的
config.BASE_URL仅在服务端可见,客户端执行代码时会拿到undefined,从而触发config.public.BASE_URL的分支,导致客户端自行拼接URL并发起请求,引发CORS。 - 虽然你同时配置了普通和公开变量,但客户端无法访问非public的运行时配置,必然会走到公开变量的逻辑。
解决方案
方案1:强制仅在服务端完成请求与数据序列化
直接利用Nuxt的SSR能力,让服务端请求完成后把数据序列化到客户端,避免客户端再次发起请求。调整代码如下:
<script setup> const route = useRoute(); const config = useRuntimeConfig(); // 仅在服务端拼接完整URL,客户端不会执行这段逻辑 let url = ''; if (process.server) { url = config.BASE_URL + route.path; } const { data } = await useFetch(url, { server: true, // 确保客户端不会重新请求 transform: (res) => res, headers: { fetchMode: 'headless', } }); </script>
方案2:使用Nitro代理(推荐)
通过Nuxt的Nitro代理,将客户端请求转发到目标API,避免跨域问题。
- 在
nuxt.config.ts中配置代理:
export default defineNuxtConfig({ runtimeConfig: { BASE_URL: process.env.BASE_URL, // 服务端专属,客户端不可见 public: { API_BASE: '/api' // 客户端请求的前缀 } }, nitro: { devProxy: { '/api': { target: process.env.BASE_URL, changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } }, // 生产环境代理配置 routeRules: { '/api/**': { proxy: `${process.env.BASE_URL}/**` } } } });
- 调整useFetch代码:
<script setup> const route = useRoute(); const config = useRuntimeConfig(); // 客户端请求代理地址,服务端直接请求真实地址 const url = process.server ? config.BASE_URL + route.path : `${config.public.API_BASE}${route.path}`; const { data } = await useFetch(url, { headers: { fetchMode: 'headless', }, server: true }); </script>
关键注意事项
- 非public的
runtimeConfig变量永远不要在客户端代码中直接引用,否则会被Nuxt视为需要暴露给客户端,导致意外行为。 - 当设置
server: true时,确保URL的拼接逻辑仅在服务端执行,避免客户端拿到可访问的API地址而发起请求。
内容的提问来源于stack exchange,提问作者Alessio Chiffi
相关产品推荐
相关产品推荐

