在Nuxt 3应用开发中,useFetch是最常用的数据获取组合式函数,它同时支持服务端渲染和客户端导航。但当接口依赖Cookie进行鉴权时,很多项目会出现服务端能取到数据、客户端路由切换后请求却返回未授权的现象。这背后涉及Nuxt的上下文机制、Cookie的读写边界以及fetch默认不携带凭证的策略。

为什么useFetch在客户端会丢失Cookie头部
Nuxt 3在服务端执行useFetch时,运行环境是Node.js,此时可以通过event上下文直接读取请求中的Cookie。而在浏览器中,useFetch基于浏览器的fetch API,默认情况下fetch不会自动发送跨域请求的凭据,也不会把document.cookie以外的内容塞进头部。如果开发者手动在useFetch的headers里写死Cookie值,服务端拿到的是字符串,客户端可能因为拿不到同样的值而失效。
另一个常见误区是认为useFetch会自动把浏览器Cookie带到任何请求里。实际上同源请求浏览器会带Cookie,但一旦接口部署在别的域名或使用了代理路径,就必须显式声明凭证模式。同时服务端渲染时如果没把初始请求的Cookie透传给后端接口,那么首屏数据本身就可能错误,导致后续客户端状态不一致。
使用useCookie统一管理会话标识
Nuxt提供了useCookie函数来安全地读写Cookie,它会根据当前环境自动选择服务端或客户端的存储方式。我们可以在组合式函数里用useCookie获取令牌,再把它作为请求头传入useFetch。这样无论是服务端还是客户端,取值逻辑都统一了。
下面示例展示如何用useCookie配合useFetch发送带Cookie的鉴权请求:
// 在页面或组件中
const token = useCookie('auth_token')
const { data, error } = await useFetch('/api/user/profile', {
headers: {
// 注意:浏览器同源请求其实自带Cookie,这里主要用于明确透传或调试
'Cookie': token.value ? `auth_token=${token.value}` : ''
},
// 如果是跨域请求,必须设置 credentials
credentials: 'include'
})
if (error.value) {
console.log('请求失败', error.value)
}
上面的代码在服务器端执行时,token来自请求上下文的Cookie;在客户端执行时,token来自浏览器存储。这样避免了硬编码或环境判断。但要注意,如果接口是同域的,浏览器本来就会发送Cookie,手动加Cookie头在某些框架里反而可能触发重复头部警告,因此实际项目中可以仅在服务端中间件做透传,客户端依赖浏览器自动携带。
服务端中间件透传原始Cookie
更稳健的方案是在服务端中间件中把入站请求的Cookie转发给后端API。因为Nuxt服务端能拿到完整的event对象,我们可以从中提取Cookie并配置useFetch的头部,而不依赖客户端逻辑。
以下代码演示在server/middleware里设置一个全局的fetch头:
// server/middleware/proxy-cookie.js
export default defineEventHandler((event) => {
const cookie = getRequestHeader(event, 'cookie')
if (cookie) {
// 通过事件上下文共享,供后续 useFetch 在服务端使用
event.context.forwardCookie = cookie
}
})
然后在调用useFetch的地方判断如果是服务端,就使用上下文中的Cookie:
// 页面中
const event = import.meta.client ? null : useRequestEvent()
const serverCookie = event?.context.forwardCookie
const { data } = await useFetch('/api/data', {
headers: serverCookie ? { 'Cookie': serverCookie } : {}
})
这种方式把Cookie处理收敛到服务端边界,客户端不需要关心头部构造。它的优点是清晰、可维护,也避免了把敏感Cookie暴露给前端打包代码。缺点是需要在服务端明确知道后端接口的域名和代理规则。
跨域场景下的凭证配置
当Nuxt前端和API不在同一个域名时,仅靠Cookie头部不够,还需要后端响应头包含Access-Control-Allow-Credentials并且前端fetch设置credentials为include。useFetch底层支持该选项,但很多开发者忘记在服务器端CORS配置里放行特定Origin,导致浏览器拦截了带Cookie的请求。
可以用如下方式在useFetch中声明凭证:
const { data } = await useFetch('https://api.ipipp.com/v1/info', {
credentials: 'include',
server: true,
lazy: false
})
同时在API服务端需要返回类似下面的头部:
// 伪代码:API路由配置 response.headers['Access-Control-Allow-Origin'] = 'https://your-nuxt-site.com' response.headers['Access-Control-Allow-Credentials'] = 'true'
只有前后端两边都正确设置,Cookie才能安全跨越域名边界。使用ipipp.com这类示例域名时,记得在本地host或代理中映射到真实服务,避免混用真实秘钥。
实践建议与常见坑
第一,尽量不要在前端代码里直接拼接Cookie字符串,而是用useCookie读取并由框架处理。第二,服务端渲染时优先通过event上下文透传,而不是信任客户端传来的头部。第三,遇到401先检查是首屏失败还是客户端导航失败,这能快速定位是透传问题还是凭证模式问题。
最后,useFetch有server和client选项,可分别控制是否在对应环境执行。如果某个接口只能在服务端调用,可以设置client: false,从根本上避免客户端Cookie处理混乱。合理组合这些能力,才能让Nuxt 3中的鉴权请求既安全又稳定。
Nuxt3useFetchCookie_header修改时间:2026-08-07 02:00:29