如何配置Node使不同(子)域名共享Cookie?
问题复盘
生产环境中MERN栈部署在Apache服务器,前端和后端分属不同子域名,导致前端通过document.cookie无法访问后端设置的Cookie;但本地环境下localhost不同端口可正常共享,核心原因是跨子域名属于不同站点,Cookie的跨域共享规则更严格。
现有配置的核心问题
当前配置存在几个关键疏漏:
- Session Cookie未指定
domain属性,浏览器只会将Cookie绑定到当前子域名,其他子域名无法读取 SameSite: 'none'要求Cookie必须启用secure: true(仅HTTPS传输),但Session Cookie设置了secure: false- 部分Cookie配置(如session、csurf)的参数不统一,导致浏览器拒绝存储
具体修正步骤
1. 统一配置Cookie的Domain属性
跨子域名共享Cookie必须将domain设为父域名(比如前端是app.example.com、后端是api.example.com,则domain为.example.com,前缀的点兼容旧浏览器)。
2. 强制SameSite=None与Secure配套使用
生产环境下必须启用HTTPS,同时将secure设为true——这是浏览器对SameSite: 'none'的硬性要求,否则Cookie会被拦截。
3. 修正Session Cookie配置
let sessionSettings = { secret: process.env.SESSION_SECRET, key: process.env.SESSION_KEY, store: sessionStore, resave: false, // 建议关闭,避免无意义的session更新 saveUninitialized: false, // 符合隐私规范,仅在需要时创建session cookie: { secure: process.env.NODE_ENV === 'production', // 生产环境自动启用Secure sameSite: 'none', domain: '.example.com', // 替换为你的实际父域名 httpOnly: true, // Session Cookie建议保持httpOnly,防止XSS攻击(前端无需访问这个Cookie) maxAge: 900000 }, }; app.use(session(sessionSettings));
4. 调整CSRF Cookie配置
确保csurf生成的Cookie符合跨子域名要求:
const protect = csurf({ cookie: { secure: process.env.NODE_ENV === 'production', sameSite: 'none', domain: '.example.com', httpOnly: false // 允许前端通过document.cookie访问XSRF-TOKEN } });
5. 前端请求必须携带Credentials
前端发起请求时,需要明确设置withCredentials: true,比如Axios:
axios.defaults.withCredentials = true;
6. 适配Apache反向代理(如果有)
若Apache作为反向代理转发请求到Node后端,需配置传递HTTPS相关头,并让Express信任代理:
- Apache配置:
RequestHeader set X-Forwarded-Proto "https" ProxyPass /api http://localhost:3000/api ProxyPassReverse /api http://localhost:3000/api
- Express添加:
app.set('trust proxy', true);
验证要点
- 检查浏览器开发者工具的Application -> Cookies,确认Cookie的Domain、Secure、SameSite属性是否符合预期
- 确认生产环境已启用HTTPS,否则
SameSite: 'none'的Cookie会被浏览器拒绝 - 前端请求的响应头中是否包含
Set-Cookie,且属性正确
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

