资讯专栏INFORMATION COLUMN

笔记:如何获取网站根域名

MasonEast / 2862人阅读

摘要:首先声明,这里所说的根域名,并不是指全球共有台根逻辑域名服务器这句话中的根域名。在本文中,我们将这样的域名称为根域名。无论访问哪个子站点,都要通过将存放到根域名下。在这种情况下,显然我们不能认为是根域名。比如一个名为的仓库。

首先声明,这里所说的“根域名”,并不是指“全球共有13台根逻辑域名服务器”这句话中的“根域名”。而是指某一个站点的“根域名”。

百度搜索是“www.baidu.com”,百度翻译的域名是“fanyi.baidu.com”,百度地图的域名则是“map.baidu.com”。这些域名有共同的部分“baidu.com”。在本文中,我们将“baidu.com”这样的域名称为“根域名”。前端同学应该都知道,在“.baidu.com”这一域下的 cookie 可以在其他子站点下拿到(当然,前提是端口号和协议都保持一致)。

最近开发的过程中遇上了一个小问题。无论访问哪个子站点,都要通过 js 将 cookie 存放到根域名下。

一开始比较大意,直接拿正则匹配。问题是忽略了这世界上还存在“www.xxx.edu.cn”这样的站点。在这种情况下,显然我们不能认为”edu.cn“是根域名。想在一个叫“edu.cn”的域下存 cookie?对不起,浏览器做不到。(这句话很重要。)

正则匹配是做不到了。搜索了一下,网上也没有什么特别好的解决方案。无非是枚举出国内常见的一些顶级域名,然后再进行处理,如下面这个 PHP 的例子:

但如何确保我们枚举出的例子一定是完全的无遗漏的呢?不完美,放弃。

PSL

接着上 github 上去找例子。倒是发现了一些解决域名的工具。比如一个名为 psl 的仓库。

PSL 是 “Public Suffix List” 的缩写,这个“公共域名后缀列表”项目本来是供浏览器厂商使用的。可以访问官网,另外建议看看这篇《域名小知识:Public Suffix List》。

我搜索到的这个 psl 仓库正是基于 PSL、使用 js 来解析域名的。粗略看了下,存放域名的 json 文件有 108 KB。吓死了。

另一款叫做 parse-domain 的,光是生成的正则表达式文件就有 203 KB。

没办法,一个跑到浏览器上的前端脚本,本身不到 1500 行,为了一个判断引入上百 KB 的外部依赖,实在不划算。

于是只能自己另起炉灶,想想别的办法。

document.domain

首先想到的是 document.domain。在一些需要跨域的场景中,可能会见到这货的身影。比如这篇文章 所描述的,“相同主域名不同子域名下的页面,可以设置 document.domain 让它们同域”。

经过测试发现,对于域名c.example.edu.cn下的页面,可以执行下面这句:

document.domain = "example.edu.cn";

而在 Chrome 下,下面这句则无法执行:

// DOMException
document.domain = "edu.cn";

浏览器会抛出DOMException

1 Uncaught DOMException: Failed to set the "domain" property on "Document": "edu.cn" is not a suffix of "c.example.edu.cn".

IE 也会报出“参数无效”的错误;Firefox 下同样会抛出错误:

NS_ERROR_DOM_BAD_DOCUMENT_DOMAIN: Illegal document.domain value

从报错信息可以看到, DOMException 是可以捕获到的。那就好办了。

将域名(或页面当前的 document.domain) split 成数据 ["x", "example", "edu", "cn"],从右向左逐次加上一个元素,每次将单词使用句点连接并赋值给 document.domain。如果 catch 到错误,则进行下一次操作。一旦赋值成功,即可 break 循环。

上代码:

const domain = document.domain;
const list = domain.split(".");

let len = list.length;
let rootDomain = domain;

while (len--) {
  try {
    document.domain = list.slice(len).join(".");
    rootDomain = document.domain;
    break;
  } catch (e) {}
}

// 还得恢复原值,避免产生副作用
document.domain = domain;

console.log(rootDomain);

很好,经过简单测试,Chrome、IE 妥妥的。

然而 Firefox 挂了。挂在最后的还原阶段。也就是说,Firefox 允许修改 document.domain,但不允许修改成上一级之后,再回退到下一级。

此外(感谢老大),在 Safari 上测试发现,document.domain = "cn" 不会报错!什么鬼?请移步《Webkit下最无敌的跨大域方案》。

功亏一篑。心好累啊。

Cookie 救火

最后想起前面提到的一句,“想在一个叫 edu.cn 的域下存 cookie?对不起,浏览器做不到。”

要不咱试试 cookie?动手!

道理同上,每次尝试在手动拼接的 domain 下面存 cookie,然后检查 cookie 是否保存成功。一旦成功,则 break 循环,并清除该 cookie。没有副作用,只是多操作几次 cookie。

换个思路,总算是解决了。

代码被我放在了 Github 上。顺手贴在这里:

var KEY = "__rT_dM__" + (+new Date());
var R = new RegExp("(^|;)s*" + KEY + "=1");
var Y1970 = (new Date(0)).toUTCString();

module.exports = function getRootDomain() {
  var domain = document.domain || location.hostname;
  var list = domain.split(".");
  var len = list.length;
  var temp = "";
  var temp2 = "";

  while (len--) {
    temp = list.slice(len).join(".");
    temp2 = KEY + "=1;domain=." + temp;

    // try to set cookie
    document.cookie = temp2;
  
    if (R.test(document.cookie)) {
      // clear
      document.cookie = temp2 + ";expires=" + Y1970;
      return temp;
    }
  }
};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/82707.html

相关文章

  • 01 【零基础入门】html学习笔记(2)

    摘要:,表单的两个常见属性为填写表单的人提供一个输入提示。可用于任何表单控件,表示这个域是必要的,如果不填,则无法提交表单。,表格,表格由行中的数据单元格组成,列隐含地定义在行中。,表格应用于表示表格数据,而不是建立页面布局。 1,如何设计一个页面 1) 先规划好web页面的结构,首先画出一个草图,然后创建一个略图,最后再写html2) 规划页面时,先设计大的块元素,再用内联元素...

    kamushin233 评论0 收藏0
  • HTTP笔记

    摘要:主要内容协议概述状态码报头协议协议是互联网使用最多的协议,是客户端和服务器请求应答的标准,端口是。一般用于与请求永久移动。今后任何新的请求都应使用新的代替未修改。 主要内容 协议概述 状态码 报头 http协议 http协议是互联网使用最多的协议,是客户端和服务器请求应答的标准TCP,端口是80。用户通过http和url统一资源定位符获取网页代码供浏览器渲染。简单快速,无连接无状态...

    maybe_009 评论0 收藏0
  • 如何对GitHubPages上的静态资源进行CDN加速

    摘要:幸运的是,采用任播技术架设镜像服务器可解决该问题,并使得实际运行的根域名服务器数量大大增加。截至年月,全球共有台根域名服务器在运行。 前记 从我开始学习前端我就一直在做着我的个人简历网站,使用GitHubpPages的预览功能进行预览,但是由于最近我的个人简历,不停的丰富,图片增多,而且将css和js文件用webpack打包后变成一个很大的问价,网页的加载速度就变的像龟速一样,所以我决...

    SHERlocked93 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<