document.domain仅影响JS同源判断,不改变Cookie发送逻辑;真正实现跨子域Session共享需服务端设Cookie domain为.example.com、前端请求带credentials: 'include',并推荐postMessage+后端同步方案。

跨子域 iframe 无法自动共享 Session,靠改 document.domain 或配 Cookie 域名只能解决部分问题,真正要让 Session 一致,必须两端协同控制 Cookie 的 domain 和 path,并确保服务器不拒绝带凭据的请求。
为什么 document.domain 不能直接解决 Session 共享
很多人以为把 document.domain = 'example.com' 就能打通 a.example.com 和 b.example.com 的 iframe 通信和 Session,其实它只影响 JavaScript 同源判断,对 HTTP 层的 Cookie 传递毫无作用。浏览器仍按原始域名发送 Cookie,a.example.com 发出的请求不会带上 b.example.com 的 Cookie,反之亦然。
常见错误现象:
- 父页在
a.example.com调用iframe.contentWindow.postMessage成功,但子 iframe 登录态仍是 guest - 子 iframe 内发 Ajax 请求返回 401,明明用户已在父页登录
-
document.cookie在子 iframe 中读不到父页设置的 session cookie
根本原因:Session ID 存在 Cookie 里,而 Cookie 默认绑定完整域名;document.domain 不改变 Cookie 的发送逻辑。
立即学习“前端免费学习笔记(深入)”;
Cookie domain 必须设为 .example.com 才生效
服务端设置 Cookie 时,Domain 属性必须显式写成以点开头的顶级域,例如 .example.com,而不是 example.com 或 a.example.com。否则浏览器不会把它发送给其他子域页面。
PHP 示例(必须在输出前执行):
ini_set('session.cookie_domain', '.example.com');
ini_set('session.cookie_path', '/');
session_start();
Node.js/Express 示例:
app.use(session({
store: store,
cookie: {
domain: '.example.com',
path: '/',
httpOnly: true,
secure: true // 生产环境必须开
}
}));
关键点:
-
domain值必须带前导点(.example.com),否则等同于不设 -
path推荐设为/,避免路径限制导致某些子路由拿不到 Cookie - 如果用了 HTTPS,
secure: true是强制项,否则浏览器拒绝发送 - 前端发请求时必须加
credentials: 'include',否则 Fetch/XHR 不带 Cookie
postMessage + 后端会话同步才是可靠组合
即使 Cookie 共享了,iframe 加载时仍可能因缓存、时序或服务端 session 失效导致状态不一致。最稳的做法是:父页用 postMessage 主动把当前 session 标识(如 userId 或加密 token)传给子 iframe,子 iframe 拿到后立即调用自己后端的 /auth/sync 接口完成会话绑定。
父页发送示例:
const iframe = document.getElementById('child');
iframe.addEventListener('load', () => {
if (iframe.contentWindow && window.sessionId) {
iframe.contentWindow.postMessage(
{ type: 'SESSION_SYNC', sessionId: window.sessionId },
'https://b.example.com'
);
}
});
子 iframe 接收并同步:
window.addEventListener('message', (e) => {
if (e.origin !== 'https://a.example.com') return;
if (e.data.type === 'SESSION_SYNC') {
fetch('/auth/sync', {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId: e.data.sessionId })
});
}
});
这样做的好处:
- 绕过 Cookie 初始加载时机问题(比如子 iframe 首屏加载时 session 还没写入)
- 服务端可做额外校验(签名、时效、IP 绑定等),比纯 Cookie 更可控
- 便于灰度或降级:某子域临时不可用时,父页可跳过发消息
容易被忽略的 Nginx 和浏览器细节
就算代码全对,Nginx 反向代理或浏览器策略也可能悄悄破坏 Cookie 传递:
- Nginx 如果用了
proxy_cookie_domain但没重写为.example.com,上游 Set-Cookie 会被覆盖成具体子域 - Chrome 95+ 对第三方 Cookie 有更严限制,若 iframe 被标记为“third-party context”(比如嵌在广告位),即使 domain 正确也可能被拦截
- 移动端 Safari 对跨子域 Cookie 支持不稳定,尤其 iOS 15 以下,建议 fallback 到 URL 参数透传 + 后端校验
- 开发时用
localhost测试要注意:它不被视为有效 domain,.localhost无效,必须用真实二级域名(如a.test.local)并配 hosts
最终效果不是“一次配置就永远好”,而是每次部署都要验证:子 iframe 的 Network 面板里,请求头是否真有 Cookie 字段,且值包含预期的 PHPSESSID 或 connect.sid —— 这才是 Session 一致性的唯一证据。



















