去年有个做电商的朋友,在调试支付回调时发现个怪事:用户在a.mall.com下单成功,却跳转到b.mall.com导致订单丢失。你猜问题出在哪?就是因为他们用错了获取主域名的方法!今天咱们就来扒一扒,这个看似简单的需求里藏着多少暗礁。
#先搞明白浏览器的小心思#
你以为直接截取window.location.hostname就能搞定?太天真啦!比如在china.site.com.cn这种带国家代码的域名里,直接split('.')会截取出错。这里有个绝活:
js**function getRootDomain let host = window.location.hostname; // 处理localhost和IP地址 if (host === 'localhost' || /^\d+\.\d+\.\d+\.\d+$/.test(host)) return host; // 处理.co.jp/.com.cn这类特殊情况 const specialTLDs = ['com.cn', 'co.jp', 'gov.tw']; const parts = host.split('.'); for(let tld of specialTLDs) { if(host.endsWith(tld) && parts.length > 2) { return parts.slice(-3).join('.'); } } return parts.slice(-2).join('.');}
这个法子能覆盖95%的常见情况,不过要特别注意:在chrome扩展程序里,window.location会返回null,得用chrome.tabs.query另取域名。
实战踩坑记录
去年给某银行做项目时,他们要求兼容这种格式:user.bank.com.hk。当时试了三个方案:
- 正则表达式**(结果把.com.hk截断成com)
- 调用第三方API(被安全部打回来)
- 最终采用的cookie反推法:
js**document.cookie = 'test_root=1; domain=.' + location.hostname + '; path=/';const isSet = document.cookie.includes('test_root');
通过设置顶级域cookie检测实际生效的域名,这个方法虽然有点骚,但完美解决了多级子域问题。不过要记得用完立即删除测试cookie!
浏览器兼容性对比表
我拿主流浏览器做了波测试:
方法 | Chrome | Firefox | Safari |
---|---|---|---|
location.hostname | ✔️ | ✔️ | ✔️ |
document.domain | 部分受限 | 正常 | 需同源 |
cookie反向探测 | ✔️ | ✔️ | 弹警告 |
Performance API | 仅HTTPS | 禁用 | 禁用 |
看清楚没?Safari对cookie操作会弹安全警告,做金融类项目千万慎用。推荐用performance.now()做备用方案,虽然精度差点但不会触发浏览器警告。
个人观点拍砖
见过最坑的需求是要兼容这种域名:a.b.c.d.example.co.uk。当时团队差点集体跑路,最后用了个邪招——调用了公共后缀列表(publicsuffix.org/list/)。不过说实话,新手千万别自己维护这个列表,光更新机制就能让你头秃三天。我的建议是:90%的场景用本文第一个方法足够,剩下10%的特殊情况,还是劝产品经理改需求更实在!