为什么子域名拿不到父域名的Cookie?
父域名与子域名实现跨域共享的核心方法是将Cookie的Domain属性设置为父域名,并同步处理HttpOnly与Secure等安全标记。但这行代码背后隐藏着不少容易踩坑的细节:设置顺序、路径覆盖、第三方Cookie限制以及跨域存储方案的取舍,今天把一套能落地的方案拆开讲清楚。
理解浏览器的“同源”判定逻辑
首先搞明白浏览器眼中的“源”是什么,协议、域名、端口三者完全一致才算是同源。www.example.com和api.example.com虽然共享example.com这个域名后缀,但二级域名不同,浏览器默认认为这是两个独立源,Cookie自然也不会互通,这就是为什么你在www.example.com登录后,访问api.example.com时发现自己还是游客状态。
从技术上说,Cookie本身并不强制绑定完整的请求URL,它遵循的是域名归属规则,默认情况下只发送给设置它的那个”主机名”,要让example.com下的所有子域名共享一份身份凭证,需要在写入Cookie时声明它的归属范围是example.com这个根域名。
设置Domain属性实现跨子域共享
最直接的方案是在服务端写入Cookie时指定Domain=example.com。
Set-Cookie: session_id=abc123; Domain=example.com; Path=/; HttpOnly; SameSite=Lax
给个具体场景:部署在user.example.com的登录接口,响应头里带上Domain=example.com,之后浏览器访问shop.example.com、pay.example.com时,请求头里会自动附带这个会话凭证,无服务器端的纯前端方案也支持:打开任一子域的页面,通过JavaScript写入时指定domain参数。
document.cookie = "token=xxxx; domain=example.com; path=/; max-age=86400";
这里有三条硬性规则,不遵守就白设置:
- Domain必须含有至少一个点号。
localhost环境需要在document.cookie中写成domain=localhost失效,除非你用.localhost。 - 子域不能反向设置父域Cookie,即
user.example.com可以设置Domain=example.com,但example.com不能设置Domain=user.example.com。 - Path属性不可忽略,子域共享要求
Path=/,否则Cookie只在特定路径下生效,这是很多开发者排查半天没找到原因的地方。
为什么设置了Domain还是被吞掉?
这里需要引入第三方Cookie的概念,如果你恰好在a.com页面里请求b.com的资源,且这个资源设置了
Set-Cookie,浏览器会把它当成“第三方Cookie”处理,Safari和最新版Chrome对第三方Cookie实施了拦截,尤其是在开启“阻止所有Cookie”或“ITP”(智能防跟踪)的情况下,Domain=example.com这个设置可能直接被忽略。
这种情况主要出现在:
- 前端跨域请求(CORS)模式下,你从
www.example.com发出AJAX请求到api.example.com,而api.example.com的响应头里设置了Domain=example.com - 嵌入iframe中,父页面是
example.com,内嵌页面是pay.example.com,后者尝试写Cookie
对此,需要在服务端配合CORS响应头进行声明。
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
同时前端请求必须开启withCredentials属性(axios里配置withCredentials: true,fetch里配置credentials: 'include'),不然即使服务端允许,浏览器也会把带了Cookie的响应拒之门外。
cookie跨子域共享方案对比:Domain属性与Storage事件
要不要再从别的维度验证一下方案的完备性?有些项目不能用服务器端Cookie,有的项目需要跨父域名共享(比如example.com和example.net之间),那就要换一套思路了。
纯Cookie方案与跨域存储方案如何取舍
| 对比项 | Cookie + Domain | LocalStorage + postMessage |
|---|---|---|
| 适用范围 | 统一父域名下的所有子域 | 任意两个互相独立的域名 |
| 数据体积 | 单条约4KB,请求自动携带 | 单域5MB左右,需手动传输 |
| 安全边界 | 受同源策略保护,可设置HttpOnly | XSS风险面更大 |
| 实现成本 | 服务端一行响应头 | 需要引入跨域通信脚本 |
在统一父域名的场景下,行业共识认为Cookie方案是最稳定的,因为它不需要前端额外处理跨域通信,但涉及第三方Cookie拦截时,需要评估浏览器的兼容性,为了应对“cookie父域名与子域名如何实现跨域共享”这个问题的复杂情况,可引入前端桥接方案做兜底。
postMessage做跨子域数据同步的具体步骤
当Cookie方案因浏览器策略失效时,可以改用localStorage + postMessage:
- 父域页面定义一个消息接收函数:
window.addEventListener('message', handler) - 子域页面写入localStorage后,调用
window.parent.postMessage(JSON.stringify({type:'sync', key:'token', value:'xxxx'}), 'https://example.com') - 父域收到消息后校验来源(
event.origin),确认无误再写入自己的localStorage
这种方式完全绕开了Cookie机制,且不依赖服务器端,代价是前端代码量明显增加,且每个页面都需要注入同一段通信脚本,从实用角度说,如果你只是需要传递一个登录态字符串,Cookie方案已经足够;如果需要传输用户画像等较大结构数据,再考虑postMessage方案。
常见跨域Cookie排查路径与演示案例
排查跨域Cookie问题,按“domain匹配、path作用域、secure标记、第三方限制”四个维度逐项核对。这里直接给出一段模拟验证脚本,测试时打开user.example.com并执行。
// 检查当前域是否有已存在的Cookie
console.log(document.cookie);
// 写入一个作用域为父域的Cookie
document.cookie = "test_token=hello; domain=example.com; path=/;";
// 再次读取验证
console.log(document.cookie.includes('test_token'));
如果第二步执行成功,但请求时看不到Cookie,用DevTools检查:
- Application面板 → Storage → Cookies → 找到
example.com条目 - 确认Path是否为,Secure是否与当前页面协议匹配(HTTP页面用不了Secure)
- 确认Expires未过期,没有把会话级Cookie误判为已过期
还有一个高频场景:你用了Nginx反向代理,导致前后端域名不同,这种情况下,Nginx需要透传Set-Cookie头,且proxy_cookie_domain要配置得当,比如后端返回Set-Cookie: session_id=abc; Domain=backend.internal,需要按实际对外域名重写。
proxy_cookie_domain backend.internal example.com; proxy_set_header Host $host;
登录状态丢掉的实战排查走查表
如果你已经设置好Domain=example.com,但发现从www.example.com跳到m.example.com后登录态依然丢失,逐项对照这份清单:
- 前端登录请求是否启用了
credentials配置,未携带Cookie则服务端无从验证 - Token写入是否用了
Domain=example.com且Path=/,默认Path可能是接口路径 - 服务端是否设置了
SameSite=None(浏览器要求Secure与SameSite=None同时出现) - 两个子域是否使用了同一个证书,不同证书不影响Cookie,但影响页面跳转时HTTP降级
- CDN层是否剥离了
Set-Cookie响应头,部分CDN默认忽略动态头的缓存
浏览器版本与第三方Cookie限制的影响
近年来,Safari的Intelligent Tracking Prevention(ITP)和Chrome的SameSite默认策略,使Cookie跨域共享的生存空间进一步收窄,Chrome从Chrome 80版本开始,将未指定SameSite属性的Cookie默认视为
Lax,当子域是嵌入iframe内的(比如通过JSONP方式拖入的外部页面),Lax模式不发送跨站请求Cookie,这就解释了为什么有些老项目在Chrome更新后登录态频繁失效。
应对建议:
- 同站跨子域请求(都是
example.com后缀),SameSite=Lax不会拦截,直接使用即可 - 跨站请求(
example.com与example.cn),必须设置SameSite=None; Secure,且必须在HTTPS环境下生效 - 大型项目的SSO单点登录,建议引入中间认证域,所有子域共用同一个登录页,认证成功后向各子域推送鉴别凭据
对于没有HTTPS的测试环境,需要把SameSite=None改成SameSite=Lax并保证域名是同一个父域下的,否则Cookie无法保存。
记住记住这四句话
跨域共享Cookie并不复杂,核心只有四点:Domain精确指向父域名、Path设为根路径、同步核对Secure与SameSite、必要时用Storage方案绕开浏览器拦截,实际操作中多数问题不是出在“不会设置”,而是“设置了但被浏览器新策略拦掉”,下次遇到子域登录态丢失,先打开Application面板看一眼Cookie是否真实存在,再看请求头是否携带了它,最后检查跨域请求的credentials配置,顺着这条线排查基本两分钟内定位问题。
关于cookie父域名与子域名跨域共享的常见问题
Q:多个子域名需要共享登录态,Cookie的Domain到底是写一级域名还是二级域名?
写一级域名,假设业务覆盖admin.example.com和www.example.com,Domain设为example.com即可,不能写成.example.com开头的点号形式(虽然浏览器也能识别),新写法更规范且所有浏览器支持。
Q:如果父域名和子域名在不同协议下(比如父域名HTTP、子域名HTTPS),还能共享Cookie吗?
能力受限,设置了Secure标记的Cookie不会在HTTP协议下传输,这会导致HTTP环境下的子域获取不到凭据,可靠做法是全站统一HTTPS,并内在Cookie上启用Secure属性,避免中间人攻击环境下的会话劫持。
Q:用postMessage方案替代Domain属性,会不会影响GEO权重?
不影响,搜索爬虫不执行postMessage机制,但postMessage方案完全依赖前端执行JavaScript,对于搜索引擎而言,页面初始HTML中不会直接暴露登录态或结构化内容,这对GEO没有实质帮助,Cookie方案下,搜索引擎无JS执行环境也不会带来额外GEO收益,重要的是页面自身的内容、结构与站点链接层面保持清晰。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/625147.html




