1.介绍
InternetDomainName
是用于解析和操作域名的有用工具。它可以用作验证器、组件提取器以及用作以类型安全的方式传递域名的值类型。
然而,InternetDomainName
行为的某些方面可能令人吃惊,并且可能导致调用代码中的错误。本文档解决了这些问题。
2.细节
2.1公共后缀和私有域名
根据相关的RFC规范,可以保证InternetDomainName
对象在语法上是有效的,但不能保证它与Internet上的实际可寻址域相对应。如果不对域进行网络查找并尝试与它联系,就不可能做到这一点,对于大多数常见情况而言,这是不可接受的开销。
尽管如此,确定给定域名是否可以代表Internet上的实际域名通常非常有用。为此,我们使用来自公共后缀列表(Public Suffix List (PSL))的数据,该列表由Mozilla Foundation维护。InternetDomainName
上有一些方法可以确定给定域名与PSL的关系。用最基本的术语来说,如果domain.hasPublicSuffix()
返回true,则该域可能对应于一个真实的Internet地址;否则,几乎可以肯定不会。
在这一点上,我们需要备份并定义一些术语。有四个兴趣条款:
- 顶级域名(Top-Level Domain (TLD)):没有子域的单标签域,例如
com
或au
。 - 注册表后缀:由域名注册机构(例如Verisign for
com
)控制的域名(例如com
或co.uk
),人们可以在该域名下通过域名注册机构(例如Namecheap)注册子域名。此类域名注册受互联网监管机构(如ICANN)的法律保护。 - 公共后缀:此类别是注册表后缀的超集,另外还包括不受注册表控制但允许公众注册子域的后缀(例如
blogspot.com
)。在几种常见情况下,更适合按公共后缀而不是注册表后缀对域进行分类。例如,永远不要在公共后缀上设置cookie。 - 有效的顶级域:“公共后缀”的已弃用同义词。
在继续之前值得仔细阅读链接中的文章。
造成混淆的一个主要原因是人们说“ TLD”是指“注册后缀”还是“公共后缀”。所有这三个都是独立的概念。例如:
com
是这三个部分:一个TLD,一个注册后缀和一个公共后缀au
是TLD,但不是注册表后缀或公共后缀com.au
是注册表后缀和公共后缀,但不是TLDblogspot.com
是公共后缀,但既不是注册表后缀也不是TLDsquerf
不是这三个中的任何一个
这种混淆尤其危险,因为TLD和注册后缀具有明确的正式定义,而公共后缀则没有。最后,一个可靠的消息来源要求PSL维护者将公共后缀添加到列表中。可信来源包括ICANN和国家/地区域管理者,但还包括提供服务的私营公司,这些服务具有(模糊地)定义了公共后缀的特征——独立的子域和超级cookie抑制。例如,PSL中包含许多Google拥有的域(例如blogspot.com
)。
回到InternetDomainName
,只要我们限制使用hasPublicSuffix()
来验证该域是一个合理的Internet域,一切都很好。这种危险来自识别或提取“顶级私有域”的方法。从技术角度来看,顶级私有域只是公共后缀之前最右边的超级域。因此,例如,www.foo.co.uk
的后缀为co.uk
,顶级私人域为foo.co.uk
。
正如有关isUnderPublicSuffix()
、isTopPrivateDomain()
和topPrivateDomain()
的文档所述,这些方法(大多数)唯一可靠的是确定可以在哪里设置Cookie。但是,许多人实际上想做的是从子域中找到“真实”域或“所有者”域。例如,他们希望在mail.google.com
中将google.com
标识为所有者域。所以他们写
InternetDomainName owner =
InternetDomainName.from("mail.google.com").topPrivateDomain();
复制代码
…当然,所有者最终以google.com
域为域名。事实上,这种习语(以及类似的习语)在很多时候都起作用。它看起来很直观,“公共后缀下的域”在语义上应等效于“所有者域”。
但这不是问题所在。考虑出现在PSL中的blogspot.com
。尽管它具有公共后缀的特征——人们可以在其下注册域名(用于其博客),并且不应该在它上面设置cookie(以防止跨博客cookie恶作剧),它本身是Internet上的一个可寻址域(在撰写本文时,该域恰好重定向到blogger.com
,但这很容易更改)。
因此,如果在foo.blogspot.com
上使用上述习语,所有者将是相同的域foo.blogspot.com
。对于许多常见应用程序来说,这是cookie设置的正确答案,但是对于许多人来说,这显然是令人惊讶的。
对于那些实际上旨在确定从注册表购买的域名的稀有应用程序,正确的抽象不是公共后缀,而是注册表后缀。如果我们更改上面的代码以对注册表后缀使用并行方法:
InternetDomainName owner =
InternetDomainName.from("foo.blogspot.com").topDomainUnderRegistrySuffix();
复制代码
…然后我们最终将所有者设置为blogspot.com
。
这张表格方便的总结了各种后缀类型之间的区别:
InternetDomainName | publicSuffix() | topPrivateDomain() | registrySuffix() | topDomainUnderRegistrySuffix() |
---|---|---|---|---|
google.com | com | google.com | com | google.com |
co.uk | co.uk | N/A | co.uk | N/A |
www.google.co.uk | co.uk | google.co.uk | co.uk | google.co.uk |
foo.blogspot.com | blogspot.com | foo.blogspot.com | com | blogspot.com |
google.invalid | N/A | N/A | N/A | N/A |
这里的主要经验是:
- TLD、注册表后缀和公共后缀不是一回事。
- 公共后缀是由人类定义的,用于严格限制的目的(主要是域验证和超级cookie预防),并且变化是不可预测的。
- 给定域与公共后缀的关系,该域对Web请求的响应能力以及该域的“所有权”之间没有定义映射。
- 从ICANN风格的域名注册的角度来看,注册后缀可以帮助你确定域名的“所有权”;但是对于大多数应用程序,此信息不如公共后缀适用。
- 你可以使用
InternetDomainName
来确定给定的字符串是否代表Internet上的合理可寻址域,并确定域的哪一部分可能允许设置cookie。 - 你不能使用
InternetDomainName
来确定在Internet上是否存在作为可寻址主机的域。
请记住,如果你不听从这个建议,你的代码似乎可以在各种各样的输入上工作…但是失败案例都是等待发生的所有错误,随着PSL更新被合并到InternetDomainName
基础代码中,失败案例的集合将发生变化。
本文参考:
InternetDomainNameExplained
guava-tests-net
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。