PublicSuffixDatabase.list 是公共后缀列表(Public Suffix List,PSL)的文件之一,以下是 PublicSuffixDatabase.list 文件及一些常见的开源处理库的介绍:
PublicSuffixDatabase.list 文件
- 概念 :公共后缀列表是一个包含所有已知公共后缀的列表,它定义了互联网上用户可以注册的域名后缀范围,这些后缀是域名体系中的公共部分,例如.com、.cn、.co.uk 等。
 - 作用 :最初是为了满足浏览器制造商的需求而创建,用于帮助浏览器解决如避免为高级域名后缀设置破坏隐私的"supercookies"、突出显示用户界面中域名最重要的部分、按站点准确排序历史记录条目等问题。现在,它已成为互联网域名管理的一项重要资源,广泛应用于网络安全、域名解析、Cookie 管理等诸多领域。
 - 维护 :由 Mozilla 发起并维护,作为社区资源,由志愿者提交和更新数据,以确保其准确性和时效性。
 - 格式 :它是一个纯文本文件,每行定义一个规则。规则主要分为三类,一类是普通规则,如 ".com" 表示所有以.com 结尾的域名都属于公共后缀;一类是以 "!" 开头的例外规则,用于表示某些特定的域名虽然符合公共后缀的规则,但实际上是可注册的域名,如 "!example.com" 表示 example.com 是一个可注册的域名,而不是公共后缀;还有一类是以 "." 开头的通配符规则,用于表示某个域及其所有子域都属于公共后缀,如 ".example.com" 表示所有以.example.com 结尾的域名都是公共后缀。
 
开源处理库
以下是部分常见的开源处理库:
PublicSuffixList JavaScript 版本
- 特性 :提供了一个简单易用的接口,可以快速判断一个域名是否属于公共后缀,并且能够解析域名的各个组成部分,如注册域、子域等。它遵循公共后缀列表的格式和规则,确保了域名解析的准确性和一致性。体积小巧,性能高效,适合在各种 JavaScript 环境中使用,包括浏览器和 Node.js。
 - 安装 :
npm install public-suffix-list。 - 使用方法
- 导入模块:
const { PublicSuffixList } = require('public-suffix-list') - 创建实例并加载默认的公共后缀列表:
const psl = new PublicSuffixList()或者const psl = PublicSuffixList.getDefault()。 - 使用方法判断域名是否有效、解析域名等,如 
psl.isValid('example.com')判断域名是否有效,psl.parse('www.example.co.uk')解析域名结构。 
 - 导入模块:
 
PublicSuffixList Ruby 版本
- 特性 :提供了丰富的功能,可以方便地判断域名是否符合公共后缀列表规则、解析域名的各个部分等。它具有良好的可读性和可维护性,便于开发者理解和使用。并且,它可以与其他 Ruby 库无缝集成,方便在 Ruby 项目中进行域名处理。
 - 安装 :
gem install public_suffix。 - 使用方法
- 需要先加载公共后缀列表,可以通过 
PublicSuffix::List.default获取默认的列表。 - 然后可以使用 
PublicSuffix::Domain.new(domain, list: list)创建一个域名对象,进而调用其方法来获取域名的各个部分,如domain.tld获取顶级域,domain.sld获取二级域等。 
 - 需要先加载公共后缀列表,可以通过 
 
PublicSuffix Python 版本
- 特性 :提供了简单易用的 API,可以方便地判断域名是否有效、解析域名的各个组成部分等。它具有良好的兼容性,能够与 Python 的其他网络库和工具无缝配合使用。同时,它的性能也较为出色,能够快速处理大量的域名数据。
 - 安装 :
pip install publicsuffixlist。 - 使用方法
- 导入模块:
from publicsuffixlist import PublicSuffixList - 创建公共后缀列表对象:
psl = PublicSuffixList()。 - 使用方法判断域名是否有效、解析域名等,如 
psl.privatesuffix(domain)判断域名是否为私有后缀,psl.get_public_suffix(domain)获取域名的公共后缀。 
 - 导入模块:
 
PublicSuffix Go 版本
- 特性 :具有高性能和高并发处理能力,能够快速处理大量的域名数据。它的代码结构清晰,易于理解和使用,并且提供了丰富的文档和示例,方便开发者快速上手。同时,它也遵循公共后缀列表的最新规范,确保了域名解析的准确性和一致性。
 - 安装 :
go get github.com/xeipuuv/go-publicsuffix。 - 使用方法
- 导入包:
import "github.com/xeipuuv/go-publicsuffix"。 - 使用函数如 
publicsuffix.List.DomainInfo(domain)来获取域名的注册管理机构信息,包括注册域、公共后缀等。 
 - 导入包:
 
PublicSuffix PHP 版本
- 特性 :提供了一个简单易用的接口,可以方便地判断域名是否符合公共后缀列表规则、解析域名的各个组成部分等。它与 PHP 的其他网络库和工具具有良好的兼容性,能够方便地集成到现有的 PHP 项目中。同时,它的代码也较为简洁,易于维护和扩展。
 - 安装 :通过 Composer 安装,
composer require "ிலவு/public-suffix"。 - 使用方法
- 导入类:
use Ilav\PublicSuffix\PublicSuffix;。 - 创建公共后缀对象:
$publicSuffix = new PublicSuffix;。 - 使用方法如 
$publicSuffix->getPublicSuffix('www.example.com')获取域名的公共后缀。 
 - 导入类:
 
OkHttp 的 PublicSuffix 包是一个可以用于处理公共后缀列表的 Kotlin 版本的开源库,其具体介绍如下:
基本情况
OkHttp 是一个流行的 HTTP 客户端库,它提供了对 HTTP 请求和响应的高效处理,而其中的 PublicSuffix 包则是专门用于处理公共后缀相关问题的。
主要功能
- 域名解析 :可以获取域名的有效顶级域名加一(Effective TLD Plus One),即注册域名,例如对于域名 "www.example.com",其有效顶级域名加一是 "example.com";对于 "shop.example.co.uk",有效顶级域名加一是 "example.co.uk"。
 - 同源策略支持 :帮助确定哪些域名应被视为 "同源",这对于确保网络安全、进行跨域资源共享(CORS)决策等非常重要。
 - 防止安全漏洞 :可阻止潜在的会话固定攻击、减少跨站请求伪造(CSRF)风险等,有助于提高网络应用的安全性。
 
使用方法
- 引入库 :在项目中添加 OkHttp 的依赖,即可引入其 PublicSuffix 包。
 - 获取 PublicSuffixDatabase 对象 :通过 
PublicSuffixDatabase.get()方法获取一个PublicSuffixDatabase对象。 - 解析域名 :调用 
PublicSuffixDatabase对象的getEffectiveTldPlusOne(domain)方法,传入需要解析的域名,即可得到该域名的有效顶级域名加一。 
跨平台设计优势
- 代码复用与平台特化的平衡 :OkHttp 的 PublicSuffix 包采用了 Kotlin Multiplatform 架构,核心逻辑在共享代码中实现,平台特定代码仅处理资源加载等平台差异,实现了 75% 的代码复用。
 - 统一 API :所有平台使用相同的接口,通过 
PublicSuffixList.Default提供统一访问点,方便开发者在不同平台上以一致的方式使用该库。 - 可扩展性 :可以轻松添加新平台支持,且平台特定优化不影响其他平台。
 - 维护性 :平台特定代码与通用代码分离,关注点分离,便于维护。
 - 性能优化 :具有延迟加载、并发处理、中断处理等性能优化措施,确保数据只在需要时加载,减少内存占用,并保证数据加载的正确性和效率。
 
使用示例
使用 OkHttp 中的 PublicSuffix 包来获取域名的有效顶级域名加一的代码示例如下:
            
            
              kotlin
              
              
            
          
          val domain1 = "www.example.com"
val result1 = PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain1)
println(result1) // 输出 example.com
val domain2 = "shop.example.co.uk"
val result2 = PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain2)
println(result2) // 输出 example.co.uk
val domain3 = "com"
val result3 = PublicSuffixDatabase.get().getEffectiveTldPlusOne(domain3)
println(result3) // 输出 null
        OkHttp PublicSuffix的后缀列表处理源码分析
1. 整体域名解析流程
此图展示了从输入域名到最终获取有效顶级域名加一级域名(eTLD+1)的完整流程。
流程图
flowchart TD
    A([开始]) --> B[输入域名]
    B --> C[转换为 Unicode]
    C --> D[拆分标签]
    D --> E[匹配公共后缀规则]
    E --> F{公共后缀?}
    F -->|是| G[返回 null]
    F -->|否| H{异常规则?}
    H -->|是| I[偏移量=标签数-规则长度]
    H -->|否| J[偏移量=标签数-规则长度-1]
    I --> K[拆分原始标签]
    J --> K
    K --> L[截取标签]
    L --> M[拼接 eTLD+1]
    M --> N[返回结果]
    G --> O([结束])
    N --> O
    
    class A,O startend
    class B,C,D,E,I,J,K,L,M process
    class F,H decision
    class G,N result
    
    classDef startend fill:#2,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#5,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#6,stroke:#FFBC52,stroke-width:2px,shape:diamond
    classDef result fill:#8,stroke:#4CAF50,stroke-width:2px
解释:
- 输入域名后,先将其转换为 Unicode 格式,再拆分成标签列表。
 - 查找匹配的公共后缀规则,判断该域名是否为公共后缀,若是则直接返回 
null。 - 若不是公共后缀,判断规则是否为异常规则,根据不同情况计算首个标签偏移量。
 - 按原始域名拆分标签列表,从偏移量位置开始截取标签并连接成字符串,最终返回 eTLD+1。
 
时序图
sequenceDiagram
    participant Client
    participant PublicSuffixDatabase
    participant PublicSuffixList
    
    Client->>PublicSuffixDatabase: getEffectiveTldPlusOne(domain)
    PublicSuffixDatabase->>PublicSuffixDatabase: 将域名转换为 Unicode
    PublicSuffixDatabase->>PublicSuffixDatabase: 拆分域名成标签列表
    PublicSuffixDatabase->>PublicSuffixDatabase: findMatchingRule(domainLabels)
    PublicSuffixDatabase->>PublicSuffixList: ensureLoaded()
    PublicSuffixList-->>PublicSuffixDatabase: 列表已加载
    PublicSuffixDatabase->>PublicSuffixList: bytes.binarySearch(...)
    PublicSuffixList-->>PublicSuffixDatabase: 匹配规则
    PublicSuffixDatabase->>PublicSuffixDatabase: 判断域名是否为公共后缀
    alt 域名是公共后缀
        PublicSuffixDatabase-->>Client: null
    else 域名不是公共后缀
        PublicSuffixDatabase->>PublicSuffixDatabase: 判断规则是否为异常规则
        PublicSuffixDatabase->>PublicSuffixDatabase: 计算首个标签偏移量
        PublicSuffixDatabase->>PublicSuffixDatabase: 按原始域名拆分标签列表
        PublicSuffixDatabase->>PublicSuffixDatabase: 从偏移量位置开始截取标签列表
        PublicSuffixDatabase->>PublicSuffixDatabase: 将截取的标签列表用点连接
        PublicSuffixDatabase-->>Client: eTLD+1
    end
解释:
- 客户端调用 
PublicSuffixDatabase的getEffectiveTldPlusOne方法。 PublicSuffixDatabase进行域名转换、拆分标签列表等操作,调用findMatchingRule方法查找匹配规则。findMatchingRule方法中会调用PublicSuffixList的ensureLoaded方法确保列表已加载,再通过binarySearch方法查找匹配规则。- 根据匹配规则判断域名是否为公共后缀,若不是则计算偏移量并处理标签列表,最终将结果返回给客户端。
 
2. 规则匹配逻辑细节
该图详细展示了查找匹配规则时,精确匹配、通配符匹配和异常匹配的处理顺序。
flowchart TD
    classDef startend fill:#4,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#5,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#6,stroke:#FFBC52,stroke-width:2px;
    
    A(开始查找规则):::process --> B(尝试精确匹配):::process
    B --> C{是否找到精确匹配?}:::decision
    C -->|是| D(记录精确匹配规则):::process
    C -->|否| E(尝试通配符匹配):::process
    D --> F(尝试异常匹配):::process
    E --> F
    F --> G{是否找到异常匹配?}:::decision
    G -->|是| H(使用异常匹配规则):::process
    G -->|否| I{精确匹配和通配符匹配哪个规则更长?}:::decision
    I -->|精确匹配长| J(使用精确匹配规则):::process
    I -->|通配符匹配长| K(使用通配符匹配规则):::process
    I -->|都未匹配| L(使用默认规则):::process
    H --> M(结束查找):::process
    J --> M
    K --> M
    L --> M
解释:
- 先进行精确匹配,若找到则记录该规则。
 - 若未找到精确匹配,进行通配符匹配。
 - 不管精确匹配是否成功,都尝试异常匹配。
 - 若找到异常匹配,优先使用该规则;否则比较精确匹配和通配符匹配规则的长度,使用较长的规则;若都未匹配,则使用默认规则。
 
3. 多段式后缀处理示例
以 www.example.co.uk 为例,展示如何处理多段式公共后缀。
graph LR
    classDef box fill:#f9f,stroke:#333,stroke-width:2px,color:#FFF
    classDef circle fill:#6f0,stroke:#FA0,stroke-width:2px,rx:15px
    
    A[[输入域名]]:::box --> B{拆分标签}
    B --> C{{识别后缀}}:::circle
    C --> D[计算eTLD+1]
    D --> E[[example.co.uk]]
解释:
- 输入域名被拆分成标签列表。
 - 查找规则时发现 
co.uk是公共后缀。 - 根据规则计算出 eTLD+1 为 
example.co.uk并输出。 
通过这些图,你可以更直观地理解公共后缀列表处理的核心逻辑和关键步骤。