React应用在Vercel上无法接收Node.js后端Cookie的问题排查
场景概述
server.vercel.app 作为 client.vercel.app 的后端服务,登录流程中服务器会生成包含JSON Web Token(JWT)的Cookie返回给客户端。本地localhost环境下通过HTTP运行前后端时,浏览器能正常看到Cookie;但部署到Vercel(HTTPS环境)后,服务器日志显示已生成Cookie,浏览器却无法查看到。客户端已配置 credentials: 'include',这是跨域携带Cookie的必要条件。
相关代码
Cookie生成代码
const token = jwt.sign({ payload: email }, process.env.TOKEN_KEY, { expiresIn: "30m", }); const serialized = cookie.serialize("token", token, { httpOnly: true, secure: process.env.NODE_ENV === "production", secure: true, sameSite: "none", maxAge: 60 * 60 * 24, path: "/", }); console.log("serialized:", serialized); res.cookie(ChatCookie, serialized);
CORS配置代码
app.use((req, res, next) => { const origin = req.headers.origin.toLowerCase(); if (origin.includes("localhost") || origin.includes("vercel.app")) { res.setHeader("Access-Control-Allow-Origin", origin); } else { console.log("setHeader", origin); } res.header("Access-Control-Allow-Methods", "DELETE, GET, POST, PUT"); res.header("Access-Control-Allow-Headers", "Content-Type, Authorization"); res.header("Access-Control-Allow-Credentials", true); return next(); });
问题排查与修复
Cookie序列化的重复配置问题
代码中重复设置了secure属性,后面的secure: true会覆盖前面的环境判断配置。虽然Vercel是HTTPS环境下该配置生效,但属于冗余写法,建议合并为一行:secure: process.env.NODE_ENV === "production",确保不同环境下的逻辑一致性。SameSite与Secure的配合逻辑
当sameSite: "none"时,浏览器强制要求Cookie必须设置secure: true(仅HTTPS环境生效),当前生产环境配置满足要求,但本地HTTP环境下如果保留sameSite: "none",浏览器会拒绝存储Cookie。建议根据环境动态设置:sameSite: process.env.NODE_ENV === "production" ? "none" : "lax"。res.cookie的使用错误(核心问题)
res.cookie()方法的设计是直接传入Cookie名称、值和配置项,它会自动处理Cookie的序列化逻辑。但当前代码先手动调用cookie.serialize()生成完整Cookie字符串,再传给res.cookie(),这会导致Cookie格式异常,浏览器无法识别存储。正确写法应为:res.cookie("token", token, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: process.env.NODE_ENV === "production" ? "none" : "lax", maxAge: 60 * 60 * 24, path: "/", });CORS头部的精准匹配
虽然当前用includes("vercel.app")能匹配客户端域名,但建议生产环境明确指定client.vercel.app作为允许的Origin,避免模糊匹配带来的潜在跨域风险。
总结
部署后浏览器无法看到Cookie的核心原因是错误使用res.cookie()方法,手动序列化Cookie字符串导致格式异常。修正该方法的调用方式,清理冗余配置,同时根据环境动态调整SameSite属性,即可解决问题。
内容的提问来源于stack exchange,提问作者user1229358

