domain属性名和其值不区分大小写,不是必须设置,可选。
名词介绍
在介绍它之前我们先介绍几个名词:
-
公共域名后缀
com和org、net、tech都是公共后缀。但是远不止这些,已知的公共后缀在这里:publicsuffix.org/list/public… 这里要注意的是,github.io也是公共的后缀,因为a.github.io和b.github.io分别代表完全不同的项目主页。a项目和b项目毫不相干,但是它们都共享github.io域名,因此github.io这种知名站点就成了公共后缀,因此a.github.io和b.github.io被samesite规则认为是不同的网站。 -
子域名和父域名:域名是继承结构的,
x.itthink.tech是itthink.tech的下级域名,itthink.tech是x.itthink.tech的上级域名。每个域名是其所有下级域名的父域名,每个域名的下级域名都算是其子域名。这里就不写精确的定义了,用复杂的定义来说一个简单的事情,反而不利于理解。相信大家通过例子已经明白什么意思了。 -
环境域名:对于在浏览器中运行的Javascript来说,它的域名环境就是当前浏览器地址栏中访问的域名。对于一个Http请求来说,它的域名环境是指当前Http请求的URL中的域名。(仅用于本文,并不是公共的名词)
有了上面的知识,咱们再来看domain代表什么意思。
domain值的限制
- domain的值必须是当前环境域名或其父域名
- 不可以是公共域名后缀
- 不可以是环境域名的子域名
- 不可以是其它域的域名,例如,环境域名为
itthink.tech时是绝对不可以设置baidu.com域名的Cookie的,因为它们属于完全不同的域。
从domain的限制来看,每个域名或许可以共享其父域名的Cookie,但是绝对不可以共享其子域名和兄弟域名的Cookie。这和继承的概念一致。
domain值的含义
按照最新的标准,domain指定的域名和其所有子域名都可以访问当前要设置的Cookie。
例如:domain=itthink.tech,代表itthink.tech和其所有子域名都可以访问当前Cookie。
但是在之前的标准中,如果希望domain所指域名的子域名也可以获取Cookie的话,需要在域名前面加.。
例如:domain=.itthink.tech代表可以支持itthink.tech和其所有子域名。
新标准对老标准进行了兼容,也就是说虽然新标准不需要前缀.,但是如果你写了前缀也是可以的。
举例总结一下:domain=itthink.tech等同于domain=.itthink.tech,均代表当前Cookie可以在itthink.tech和其环境子域名下被访问。这两种写法均得到了所有主流浏览器的支持。
端口不在Cookie的考虑范围内
在URL中,域名后面有时候会带上端口,一般情况下,域名相同端口不同会指向不同的服务,按理说Cookie是不应该共享的,但是实际情况是,Cookie完全忽略端口的存在,Cookie不具有端口隔离性。这个是Cookie弱点之一。
举例如下:
www.itthink.tech:8080和www.itthink.tech:3000,这两个域名对于Cookie来说没有区别,它们的Cookie是共享的。
document.cookie并不能获取domain
大家对document.cookie的理解会有一个重大的误区。
因为设置document.cookie时会有各种Cookie的属性,所以大家理所当然的认为通过读取document.cookie也可以获取Cookie的属性。
这是一个很容易犯的错误。事实上读取document.cookie时,只能读取到当前环境下允许的Cookie的名字和值,Cookie的属性是无法读取的,包括domain属性。
document.cookie不是一个普通的属性,设置和读取它,会触发setter和getter。向document.cookie赋值和读取document.cookie的值,两个值是不一样的概念。
事实上JavaScript目前还没有办法获取到Cookie的任何属性或者叫元数据,包括domain。
即使是服务端,也无法从HTTP请求中获取到Cookie的属性。
举例如下:
document.cookie = `token=token2; domain=itthink.tech`;
// 将变成:token=token2
console.log(document.cookie);
可以看到读取document.cookie只能读取到当前环境允许的Cookie的名字和值。
不设置domain的情况
domain如果不设置,也具有特殊的意义。此时的Cookie是Host-Only的,也就是说只有当前环境域名可以访问。假设我们的环境域名是itthink.tech,那domain的默认值就是itthink.tech,这里要注意的是,它和domain=itthink.tech并不是一回事,domain=itthink.tech代表itthink.tech和其子域名,而如果不设置domain则代表仅仅是itthink.tech。
不过之前的Edge版本和IE11之前的版本是例外,如果不设置domain,当前Cookie将适用于当前环境域名和所有其子域名。
去除点前缀带来的小混乱
新标准去除了前缀.给Cookiedomain的设置带来了一点歧义。
举例说明如下:
假设我们在itthink.tech网站的调试控制台中运行:document.cookie = 'x=y; domain=itthink.tech',调试工具的控制面板一般会显示成以下这样:
可以看到
domain那一项变成了.itthink.tech。浏览器为什么还要使用被废弃的老标准来显示domain字段呢?
假设我们暂且显示成itthink.tech,这时我们再设置一个不带domain的新Cookie,这时的domain栏应该显示为空,但是空的话用户在查看该面板时就无法知道这个Cookie属于哪个域名,所以需要显示其默认值itthink.tech,也就是说没有设置domain时,domain栏显示了itthink.tech,而且这个Cookie是Host-Only的,仅当前域名可以使用该Cookie,而当显式的设置domain为itthink.tech时,这个Cookie并不是Host-Only的,但是其值如果也显示成itthink.tech,则无法通过domain栏位来区分是否是Host-Only的,所以浏览器通过加.的方式来区分,有.前缀的表示指定域名和其子域名均可共享该Cookie,没有的表示当前Cookie没有设置domain,是Host-Only的。
Cookie是按域隔离的
domain就像是Cookie的命名空间一样,即使Cookie的名称相同,只要domain不同,它们就不会被合并读出,它们会被分别读出来。
例如x.itthink.tech网站,分别设置Cookie如下:
document.cookie = `token=token1;`;
document.cookie = `token=token2; domain=itthink.tech`;
document.cookie = `token=token3; domain=x.itthink.tech`;
console.log(document.cookie);
// 输出 token=token1; token=token2; token=token3
// 各个浏览器的输出顺序不一定一致
它们都有相同的Cookie名称,但是domain不同,这时document.cookie会输出三个token,各个浏览器的输出顺序不一定一致。Http也是一样的情况。
这种情况想必是我们要尽量避免的,大家一定要小心。
修改Cookie的注意点
修改Cookie时一定要注意,修改时的domain必须和之前设置的domain相同。
例如Cookietoken=afdsaf; domain=itthink.tech,我们通过重新设置来修改它:token=gggd; domain=www.itthink.tech;这里使用了不同的domain,实际执行时将无法修改之前的token,而是新添加了一个叫token的Cookie,它的domain是www.itthink.tech。
总结
domain属性是Cookie中一等重要的属性,大家在设置Cookie时一定不要忘记设置domain,否则容易带来意想不到的Bug。
此篇结束。